int SplashDecodePng(Splash * splash, png_rw_ptr read_func, void *io_ptr) { int stride; ImageFormat srcFormat; png_uint_32 i, rowbytes; png_bytepp row_pointers = NULL; png_bytep image_data = NULL; int success = 0; double gamma; png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_uint_32 width, height; int bit_depth, color_type; ImageRect srcRect, dstRect; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { goto done; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { goto done; } #ifdef __APPLE__ /* use setjmp/longjmp versions that do not save/restore the signal mask */ if (_setjmp(png_set_longjmp_fn(png_ptr, _longjmp, sizeof(jmp_buf)))) { #else if (setjmp(png_jmpbuf(png_ptr))) { #endif goto done; } png_set_read_fn(png_ptr, io_ptr, read_func); png_set_sig_bytes(png_ptr, SIG_BYTES); /* we already read the 8 signature bytes */ png_read_info(png_ptr, info_ptr); /* read all PNG info up to image data */ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits, * transparency chunks to full alpha channel; strip 16-bit-per-sample * images to 8 bits per sample; and convert grayscale to RGB[A] * this may be sub-optimal but this simplifies implementation */ png_set_expand(png_ptr); png_set_tRNS_to_alpha(png_ptr); png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); png_set_strip_16(png_ptr); png_set_gray_to_rgb(png_ptr); if (png_get_gAMA(png_ptr, info_ptr, &gamma)) png_set_gamma(png_ptr, 2.2, gamma); png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); rowbytes = png_get_rowbytes(png_ptr, info_ptr); if (!SAFE_TO_ALLOC(rowbytes, height)) { goto done; } if ((image_data = (unsigned char *) malloc(rowbytes * height)) == NULL) { goto done; } if (!SAFE_TO_ALLOC(height, sizeof(png_bytep))) { goto done; } if ((row_pointers = (png_bytepp) malloc(height * sizeof(png_bytep))) == NULL) { goto done; } for (i = 0; i < height; ++i) row_pointers[i] = image_data + i * rowbytes; png_read_image(png_ptr, row_pointers); SplashCleanup(splash); splash->width = width; splash->height = height; if (!SAFE_TO_ALLOC(splash->width, splash->imageFormat.depthBytes)) { goto done; } stride = splash->width * splash->imageFormat.depthBytes; if (!SAFE_TO_ALLOC(splash->height, stride)) { goto done; } splash->frameCount = 1; splash->frames = (SplashImage *) malloc(sizeof(SplashImage) * splash->frameCount); if (splash->frames == NULL) { goto done; } splash->loopCount = 1; splash->frames[0].bitmapBits = malloc(stride * splash->height); if (splash->frames[0].bitmapBits == NULL) { free(splash->frames); goto done; } splash->frames[0].delay = 0; /* FIXME: sort out the real format */ initFormat(&srcFormat, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF); srcFormat.byteOrder = BYTE_ORDER_MSBFIRST; initRect(&srcRect, 0, 0, width, height, 1, rowbytes, image_data, &srcFormat); initRect(&dstRect, 0, 0, width, height, 1, stride, splash->frames[0].bitmapBits, &splash->imageFormat); convertRect(&srcRect, &dstRect, CVT_COPY); SplashInitFrameShape(splash, 0); png_read_end(png_ptr, NULL); success = 1; done: free(row_pointers); free(image_data); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return success; } int SplashDecodePngStream(Splash * splash, SplashStream * stream) { unsigned char sig[SIG_BYTES]; int success = 0; stream->read(stream, sig, SIG_BYTES); if (png_sig_cmp(sig, 0, SIG_BYTES)) { goto done; } success = SplashDecodePng(splash, my_png_read_stream, stream); done: return success; }
int Read ( byte **data, int *width, int *height ) { // Setup the pointers *data = NULL; *width = 0; *height = 0; // Make sure we're actually reading PNG data. const int SIGNATURE_LEN = 8; byte ident[SIGNATURE_LEN]; memcpy (ident, buf, SIGNATURE_LEN); if ( !png_check_sig (ident, SIGNATURE_LEN) ) { ri->Printf (PRINT_ERROR, "PNG signature not found in given image."); return 0; } png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, png_print_error, png_print_warning); if ( png_ptr == NULL ) { ri->Printf (PRINT_ERROR, "Could not allocate enough memory to load the image."); return 0; } info_ptr = png_create_info_struct (png_ptr); if ( setjmp (png_jmpbuf (png_ptr)) ) { return 0; } // We've read the signature offset += SIGNATURE_LEN; // Setup reading information, and read header png_set_read_fn (png_ptr, (png_voidp)this, &user_read_data); #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED // This generic "ignore all, except required chunks" requires 1.6.0 or newer" png_set_keep_unknown_chunks (png_ptr, PNG_HANDLE_CHUNK_NEVER, NULL, -1); #endif png_set_sig_bytes (png_ptr, SIGNATURE_LEN); png_read_info (png_ptr, info_ptr); png_uint_32 width_; png_uint_32 height_; int depth; int colortype; png_get_IHDR (png_ptr, info_ptr, &width_, &height_, &depth, &colortype, NULL, NULL, NULL); // While modern OpenGL can handle non-PoT textures, it's faster to handle only PoT // so that the graphics driver doesn't have to fiddle about with the texture when uploading. /* if ( !IsPowerOfTwo (width_) || !IsPowerOfTwo (height_) ) { ri->Printf (PRINT_ERROR, "Width or height is not a power-of-two.\n"); return 0; } */ // This function is equivalent to using what used to be LoadPNG32. LoadPNG8 also existed, // but this only seemed to be used by the RMG system which does not work in JKA. If this // does need to be re-implemented, then colortype should be PNG_COLOR_TYPE_PALETTE or // PNG_COLOR_TYPE_GRAY. if ( colortype != PNG_COLOR_TYPE_RGB && colortype != PNG_COLOR_TYPE_RGBA ) { ri->Printf (PRINT_ERROR, "Image is not 24-bit or 32-bit."); return 0; } // Read the png data if ( colortype == PNG_COLOR_TYPE_RGB ) { // Expand RGB -> RGBA png_set_add_alpha (png_ptr, 0xff, PNG_FILLER_AFTER); } png_read_update_info (png_ptr, info_ptr); // We always assume there are 4 channels. RGB channels are expanded to RGBA when read. byte *tempData = (byte *)ri->Z_Malloc (width_ * height_ * 4, TAG_TEMP_PNG, qfalse, 4); if ( !tempData ) { ri->Printf (PRINT_ERROR, "Could not allocate enough memory to load the image."); return 0; } // Dynamic array of row pointers, with 'height' elements, initialized to NULL. byte **row_pointers = (byte **)ri->Hunk_AllocateTempMemory (sizeof (byte *) * height_); if ( !row_pointers ) { ri->Printf (PRINT_ERROR, "Could not allocate enough memory to load the image."); ri->Z_Free (tempData); return 0; } // Re-set the jmp so that these new memory allocations can be reclaimed if ( setjmp (png_jmpbuf (png_ptr)) ) { ri->Hunk_FreeTempMemory (row_pointers); ri->Z_Free (tempData); return 0; } for ( unsigned int i = 0, j = 0; i < height_; i++, j += 4 ) { row_pointers[i] = tempData + j * width_; } png_read_image (png_ptr, row_pointers); // Finish reading png_read_end (png_ptr, NULL); ri->Hunk_FreeTempMemory (row_pointers); // Finally assign all the parameters *data = tempData; *width = width_; *height = height_; return 1; }
void png_reader::init() { FILE *fp=fopen(fileName_.c_str(),"rb"); if (!fp) throw image_reader_exception("cannot open image file "+fileName_); png_byte header[8]; memset(header,0,8); if ( fread(header,1,8,fp) != 8) { fclose(fp); throw image_reader_exception("Could not read " + fileName_); } int is_png=!png_sig_cmp(header,0,8); if (!is_png) { fclose(fp); throw image_reader_exception(fileName_ + " is not a png file"); } png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,0,0,0); if (!png_ptr) { fclose(fp); throw image_reader_exception("failed to allocate png_ptr"); } // catch errors in a custom way to avoid the need for setjmp png_set_error_fn(png_ptr, png_get_error_ptr(png_ptr), user_error_fn, user_warning_fn); png_infop info_ptr; try { info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr,0,0); fclose(fp); throw image_reader_exception("failed to create info_ptr"); } } catch (std::exception const& ex) { png_destroy_read_struct(&png_ptr,0,0); fclose(fp); throw; } png_set_read_fn(png_ptr, (png_voidp)fp, png_read_data); png_set_sig_bytes(png_ptr,8); png_read_info(png_ptr, info_ptr); png_uint_32 width, height; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth_, &color_type_,0,0,0); width_=width; height_=height; MAPNIK_LOG_DEBUG(png_reader) << "png_reader: bit_depth=" << bit_depth_ << ",color_type=" << color_type_; png_destroy_read_struct(&png_ptr,&info_ptr,0); fclose(fp); }
/* ReadPNG - Reads the contents of a PNG file and stores the contents into BMGImageStruct Inputs: filename - the name of the file to be opened Outputs: img - the BMGImageStruct containing the image data Returns: BMGError - if the file could not be read or a resource error occurred BMG_OK - if the file was read and the data was stored in img Limitations: None. Comments: 2-bit images are converted to 4-bit images. 16-bit images are converted to 8-bit images. gray scale images with alpha components are converted to 32-bit images */ BMGError ReadPNG( const char *filename, struct BMGImageStruct * volatile img ) { jmp_buf err_jmp; int error; FILE * volatile file = NULL; int BitDepth; int ColorType; int InterlaceType; unsigned char signature[8]; png_structp volatile png_ptr = NULL; png_infop volatile info_ptr = NULL; png_infop volatile end_info = NULL; png_color_16 *ImageBackground = NULL; png_bytep trns = NULL; int NumTrans = 0; int i, k; png_color_16p TransColors = NULL; png_uint_32 Width, Height; unsigned char *bits; unsigned char** volatile rows = NULL; BMGError tmp; /* error handler */ error = setjmp( err_jmp ); if (error != 0) { if (end_info != NULL) png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info); else if (info_ptr != NULL) png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, NULL); else if (png_ptr != NULL) png_destroy_read_struct((png_structp *) &png_ptr, NULL, NULL); if (rows) { if (rows[0]) free(rows[0]); free(rows); } if (img) FreeBMGImage(img); if (file) fclose(file); SetLastBMGError((BMGError) error); return (BMGError) error; } if ( img == NULL ) longjmp ( err_jmp, (int)errInvalidBMGImage ); file = fopen( filename, "rb" ); if ( !file || fread( signature, 1, 8, file ) != 8) longjmp ( err_jmp, (int)errFileOpen ); /* check the signature */ if ( png_sig_cmp( signature, 0, 8 ) != 0 ) longjmp( err_jmp, (int)errUnsupportedFileFormat ); /* create a pointer to the png read structure */ png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); if ( !png_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create a pointer to the png info structure */ info_ptr = png_create_info_struct( png_ptr ); if ( !info_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create a pointer to the png end-info structure */ end_info = png_create_info_struct(png_ptr); if (!end_info) longjmp( err_jmp, (int)errMemoryAllocation ); /* bamboozle the PNG longjmp buffer */ /*generic PNG error handler*/ /* error will always == 1 which == errLib */ // error = png_setjmp(png_ptr); error = setjmp( png_jmpbuf( png_ptr ) ); if ( error > 0 ) longjmp( err_jmp, error ); /* set function pointers in the PNG library, for read callbacks */ png_set_read_fn(png_ptr, (png_voidp) file, user_read_data); /*let the read functions know that we have already read the 1st 8 bytes */ png_set_sig_bytes( png_ptr, 8 ); /* read all PNG data up to the image data */ png_read_info( png_ptr, info_ptr ); /* extract the data we need to form the HBITMAP from the PNG header */ png_get_IHDR( png_ptr, info_ptr, &Width, &Height, &BitDepth, &ColorType, &InterlaceType, NULL, NULL); img->width = (unsigned int) Width; img->height = (unsigned int) Height; img->bits_per_pixel = (unsigned char)32; img->scan_width = Width * 4; /* convert 16-bit images to 8-bit images */ if (BitDepth == 16) png_set_strip_16(png_ptr); /* These are not really required per Rice format spec, * but is done just in case someone uses them. */ /* convert palette color to rgb color */ if (ColorType == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); ColorType = PNG_COLOR_TYPE_RGB; } /* expand 1,2,4 bit gray scale to 8 bit gray scale */ if (ColorType == PNG_COLOR_TYPE_GRAY && BitDepth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); /* convert gray scale or gray scale + alpha to rgb color */ if (ColorType == PNG_COLOR_TYPE_GRAY || ColorType == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); ColorType = PNG_COLOR_TYPE_RGB; } /* add alpha channel if any */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); ColorType = PNG_COLOR_TYPE_RGB_ALPHA; } /* convert rgb to rgba */ if (ColorType == PNG_COLOR_TYPE_RGB) { png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); ColorType = PNG_COLOR_TYPE_RGB_ALPHA; } png_set_bgr(png_ptr); /* set the background color if one is found */ if ( png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD) ) png_get_bKGD(png_ptr, info_ptr, &ImageBackground); /* get the transparent color if one is there */ if ( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) ) png_get_tRNS( png_ptr, info_ptr, &trns, &NumTrans, &TransColors ); img->palette_size = (unsigned short)0; img->bytes_per_palette_entry = 4U; tmp = AllocateBMGImage( img ); if ( tmp != BMG_OK ) longjmp( err_jmp, (int)tmp ); png_read_update_info( png_ptr, info_ptr ); /* create buffer to read data to */ rows = (unsigned char **)malloc(Height*sizeof(unsigned char *)); if ( !rows ) longjmp( err_jmp, (int)errMemoryAllocation ); k = png_get_rowbytes( png_ptr, info_ptr ); rows[0] = (unsigned char *)malloc( Height*k*sizeof(char)); if ( !rows[0] ) longjmp( err_jmp, (int)errMemoryAllocation ); for ( i = 1; i < (int)Height; i++ ) rows[i] = rows[i-1] + k; /* read the entire image into rows */ png_read_image( png_ptr, rows ); bits = img->bits + (Height - 1) * img->scan_width; for ( i = 0; i < (int)Height; i++ ) { memcpy(bits, rows[i], 4*Width); bits -= img->scan_width; } free( rows[0] ); free( rows ); png_read_end( png_ptr, info_ptr ); png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info); fclose( file ); return BMG_OK; }
/** * @brief Opens an npng struct from an SDL_RWops. It does not close the RWops. * * @param rw SDL_RWops to create npng from. * @return npng created from rw. */ npng_t *npng_open( SDL_RWops *rw ) { png_byte header[8]; /* Maximum size to check. */ npng_t *npng; /* Allocate memory. */ npng = malloc( sizeof(npng_t) ); if (npng == NULL) { WARN("Out of memory."); return NULL; } memset( npng, 0, sizeof(npng_t) ); /* Set up struct. */ npng->rw = rw; npng->png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); if (npng->png_ptr == NULL) { WARN("png_create_read_struct failed"); goto ERR_FAIL; } npng->info_ptr = png_create_info_struct( npng->png_ptr ); if (npng->info_ptr == NULL) { WARN("png_create_info_struct failed"); goto ERR_FAIL; } /* Check header. */ SDL_RWread( rw, header, 8, 1 ); if (png_sig_cmp(header, 0, 8)) { WARN("RWops not recognized as a PNG file."); goto ERR_FAIL; } /* Set up for reading. */ png_set_read_fn( npng->png_ptr, (png_voidp) rw, npng_read ); /* Set up long jump for IO. */ if (setjmp( png_jmpbuf( npng->png_ptr )) ) { WARN("Error during setjmp"); goto ERR_FAIL; } /* We've already checked sig. */ png_set_sig_bytes( npng->png_ptr, 8 ); /* Get start. */ npng->start = SDL_RWtell( npng->rw ); /* Get info. */ npng_info( npng ); /* Load text. */ png_get_text( npng->png_ptr, npng->info_ptr, &npng->text_ptr, &npng->num_text ); return npng; ERR_FAIL: #if 0 /* Memory leaks are better than segfaults. */ if (npng != NULL) { if (npng->png_ptr != NULL) png_destroy_read_struct( &npng->png_ptr, (npng->info_ptr != NULL) ? &npng->info_ptr : NULL, NULL ); free(npng); } #endif return NULL; }
// load in the image data IImage* CImageLoaderPng::loadImage(irr::io::IReadFile* file) { #ifdef _IRR_COMPILE_WITH_LIBPNG_ if (!file) return 0; Image = 0; 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 // Extract info png_get_IHDR(png_ptr, info_ptr, (png_uint_32*)&Width, (png_uint_32*)&Height, &BitDepth, &ColorType, NULL, NULL, NULL); // 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_ }
int ImageFormatPNG::load(const char *name, int& width, int& height, int& format) { printf("ImageFormatPNG::load\n"); // Open File FILE* file = fopen(name,"rb"); if (file == 0) { printf("ImageFormatPNG::load(): can't open file '%s'\n",name); return 0; } // init width / height / format value to 0 width = 0; height = 0; format = 0; //Allocate a buffer of 8 bytes, where we can put the file signature. png_byte sig[8]; //Read the 8 bytes from the file into the sig buffer. fread((char*)sig, sizeof(png_byte), 8, file); if(!png_check_sig(sig,8)) { fclose(file); return 0; } //Here we create the png read struct. png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if(pngPtr == 0) { fclose(file); return 0; } //Here we create the png info struct. png_infop infoPtr = png_create_info_struct(pngPtr); if(infoPtr == 0) { png_destroy_read_struct(&pngPtr, (png_infopp)0, (png_infopp)0); fclose(file); return 0; } png_set_read_fn(pngPtr,file, file_read_function); //Set the amount signature bytes we've already read: png_set_sig_bytes(pngPtr, 8); //Now call png_read_info with our pngPtr as image handle, and infoPtr to receive the file info. png_read_info(pngPtr, infoPtr); png_uint_32 imgWidth = png_get_image_width(pngPtr, infoPtr); png_uint_32 imgHeight = png_get_image_height(pngPtr, infoPtr); //bits per CHANNEL! note: not per pixel! png_uint_32 bitdepth = png_get_bit_depth(pngPtr, infoPtr); //Number of channels png_uint_32 channels = png_get_channels(pngPtr, infoPtr); //Color type. (RGB, RGBA, Luminance, luminance alpha... palette... etc) png_uint_32 color_type = png_get_color_type(pngPtr, infoPtr); switch (color_type) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(pngPtr); //Don't forget to update the channel info (thanks Tom!) //It's used later to know how big a buffer we need for the image channels = 3; break; case PNG_COLOR_TYPE_GRAY: if (bitdepth < 8) png_set_expand_gray_1_2_4_to_8(pngPtr); //And the bitdepth info bitdepth = 8; break; } /*if the image has a transperancy set.. convert it to a full Alpha channel..*/ if (png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(pngPtr); channels+=1; } //We don't support 16 bit precision.. so if the image Has 16 bits per channel //precision... round it down to 8. if (bitdepth == 16) png_set_strip_16(pngPtr); //Array of row pointers. One for every row. png_bytep* rowPtrs = new png_bytep[imgHeight]; width = imgWidth; height = imgHeight; format = bitdepth * channels / 8; int data_decoded_size = width * height * format; // raw data image container unsigned char * img_data_decoded = new unsigned char[data_decoded_size]; memset(img_data_decoded,0x00,data_decoded_size + 1); int stride = width * format; for (size_t i = 0; i < imgHeight; i++) { //Set the pointer to the data pointer + i times the row stride. png_uint_32 q = (imgHeight- i - 1) * stride; rowPtrs[i] = (png_bytep)img_data_decoded + q; } //And here it is! The actuall reading of the image! png_read_image(pngPtr, rowPtrs); //Delete the row pointers array.... delete[] (png_bytep)rowPtrs; //And don't forget to clean up the read and info structs ! png_destroy_read_struct(&pngPtr, &infoPtr,(png_infopp)0); // create temporary file for glue code javascript ImageFormat::flip_y((unsigned char *)img_data_decoded,width,height,format); FILE* raw = fopen(kTempararyName,"wb"); if (raw) { fwrite(img_data_decoded,width * height * format ,1 , raw); fclose(raw); } delete img_data_decoded; fclose(file); return 1; }
bool BitmapData::initWithPNGData(const unsigned char *data, ssize_t size) { static const int PNGSIGSIZE = 8; png_byte header[PNGSIGSIZE] = {0}; png_structp png_ptr = 0; png_infop info_ptr = 0; memcpy(header, data, PNGSIGSIZE); if (png_sig_cmp(header, 0, PNGSIGSIZE) != 0) { return false; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); info_ptr = png_create_info_struct(png_ptr); setjmp(png_jmpbuf(png_ptr)); PngSource pngSource; pngSource.data = (unsigned char*)data; pngSource.size = size; pngSource.offset = 0; png_set_read_fn(png_ptr, &pngSource, pngReadCallback); 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); png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr); png_uint_32 color_type = png_get_color_type(png_ptr, info_ptr); if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { bit_depth = 8; } 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 (bit_depth < 8) { png_set_packing(png_ptr); } // update info png_read_update_info(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); switch (color_type) { case PNG_COLOR_TYPE_GRAY: _renderFormat = Texture2D::PixelFormat::I8; break; case PNG_COLOR_TYPE_GRAY_ALPHA: _renderFormat = Texture2D::PixelFormat::AI88; break; case PNG_COLOR_TYPE_RGB: _renderFormat = Texture2D::PixelFormat::RGB888; break; case PNG_COLOR_TYPE_RGB_ALPHA: _renderFormat = Texture2D::PixelFormat::RGBA8888; break; default: break; } // read png data png_size_t rowbytes; png_bytep* row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * _height); rowbytes = png_get_rowbytes(png_ptr, info_ptr); _dataSize = rowbytes * _height; _data = static_cast<unsigned char*>(malloc(_dataSize * sizeof(unsigned char))); if(!_data) { if (row_pointers != nullptr) { free(row_pointers); } return false; } for (unsigned short i = 0; i < _height; ++i) { row_pointers[i] = _data + i*rowbytes; } png_read_image(png_ptr, row_pointers); png_read_end(png_ptr, nullptr); if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) { _alpha = true; } else { _alpha = false; } if (row_pointers != nullptr) { free(row_pointers); } if (png_ptr) { png_destroy_read_struct(&png_ptr, (info_ptr) ? &info_ptr : 0, 0); } return true; }
uint8_t* GraphicsTexture::loadImage() { Pegas_log_info("GraphicsTexture::loadImage"); Resource::AutoDispose autoDispose(mResource); if (mResource.open() != STATUS_OK) { Pegas_log_error("mResource.open failed"); return NULL; } png_byte header[8]; if (mResource.read(header, sizeof(header)) != STATUS_OK) { Pegas_log_error("mResource.read failed"); return NULL; } if (png_sig_cmp(header, 0, 8) != 0) { Pegas_log_error("png_sig_cmp failed, header param: %s", header); return NULL; } png_structp pngMain = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!pngMain) { Pegas_log_error("png_create_read_struct failed"); return NULL; } png_infop pngInfo = png_create_info_struct(pngMain); if (!pngInfo) { Pegas_log_error("png_create_info_struct failed"); return NULL; } png_set_read_fn(pngMain, &mResource, callback_read); if (setjmp(png_jmpbuf(pngMain))) { Pegas_log_error("setjmp failed"); return NULL; } png_set_sig_bytes(pngMain, 8); png_read_info(pngMain, pngInfo); png_int_32 depth, colorType; png_uint_32 width, height; png_get_IHDR(pngMain, pngInfo, &width, &height, &depth, &colorType, NULL, NULL, NULL); mWidth = width; mHeight = height; bool transparency = false; // Creates a full alpha channel if transparency is encoded as // an array of palette entries or a single transparent color. if (png_get_valid(pngMain, pngInfo, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(pngMain); transparency = true; Pegas_log_error("png_get_valid failed"); return NULL; } // Expands PNG with less than 8bits per channel to 8bits. if (depth < 0) { png_set_packing(pngMain); // Shrinks PNG with 16bits per color channel down to 8bits. } else if (depth == 16) { png_set_strip_16(pngMain); } // Indicates that image needs conversion to RGBA if needed. switch (colorType) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(pngMain); mFormat = transparency ? GL_RGBA : GL_RGB; break; case PNG_COLOR_TYPE_RGB: mFormat = transparency ? GL_RGBA : GL_RGB; break; case PNG_COLOR_TYPE_RGBA: mFormat = GL_RGBA; break; case PNG_COLOR_TYPE_GRAY: png_set_expand_gray_1_2_4_to_8(pngMain); mFormat = transparency ? GL_LUMINANCE_ALPHA : GL_LUMINANCE; break; case PNG_COLOR_TYPE_GA: png_set_expand_gray_1_2_4_to_8(pngMain); mFormat = GL_LUMINANCE_ALPHA; break; } png_read_update_info(pngMain, pngInfo); png_int_32 rowSize = png_get_rowbytes(pngMain, pngInfo); if (rowSize <= 0) { Pegas_log_error("invalid png row size: %d", rowSize); return NULL; } png_byte* imageBuffer = new png_byte[rowSize * height]; if (!imageBuffer) { Pegas_log_error("can not allocate image buffer"); return NULL; } png_bytep* rowPtrs = new png_bytep[height]; if (!rowPtrs) { Pegas_log_error("can not allocate row pointers"); //TODO: use smart pointer for this delete[] imageBuffer; return NULL; } for (int32_t i = 0; i < height; ++i) { rowPtrs[height - (i + 1)] = imageBuffer + (i * rowSize); } png_read_image(pngMain, rowPtrs); png_destroy_read_struct(&pngMain, &pngInfo, NULL); delete[] rowPtrs; return imageBuffer; }
static HPDF_STATUS LoadPngData (HPDF_Dict image, HPDF_Xref xref, HPDF_Stream png_data, HPDF_BOOL delayed_loading) { HPDF_STATUS ret = HPDF_OK; png_uint_32 width, height; int bit_depth, color_type; png_structp png_ptr = NULL; png_infop info_ptr = NULL; HPDF_PTRACE ((" HPDF_Image_LoadPngImage\n")); /* create read_struct. */ png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, image->error, PngErrorFunc, NULL); if (png_ptr == NULL) { HPDF_SetError (image->error, HPDF_FAILD_TO_ALLOC_MEM, 0); return HPDF_FAILD_TO_ALLOC_MEM; } /* create info-struct */ info_ptr = png_create_info_struct (png_ptr); if (info_ptr == NULL) { HPDF_SetError (image->error, HPDF_FAILD_TO_ALLOC_MEM, 0); goto Exit; } png_set_sig_bytes (png_ptr, HPDF_PNG_BYTES_TO_CHECK); png_set_read_fn (png_ptr, (void *)png_data, (png_rw_ptr)&PngReadFunc); /* reading info structure. */ png_read_info(png_ptr, info_ptr); if (image->error->error_no != HPDF_OK) { goto Exit; } png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); /* 16bit images are not supported. */ if (bit_depth == 16) { png_set_strip_16(png_ptr); } png_read_update_info(png_ptr, info_ptr); if (image->error->error_no != HPDF_OK) { goto Exit; } /* check palette-based images for transparent areas and load them immediately if found */ if (xref && PNG_COLOR_TYPE_PALETTE & color_type) { png_bytep trans; int num_trans; HPDF_Dict smask; png_bytep smask_data; if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) || !png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL)) { goto no_transparent_color_in_palette; } smask = HPDF_DictStream_New (image->mmgr, xref); if (!smask) { ret = HPDF_FAILD_TO_ALLOC_MEM; goto Exit; } smask->header.obj_class |= HPDF_OSUBCLASS_XOBJECT; ret = HPDF_Dict_AddName (smask, "Type", "XObject"); ret += HPDF_Dict_AddName (smask, "Subtype", "Image"); ret += HPDF_Dict_AddNumber (smask, "Width", (HPDF_UINT)width); ret += HPDF_Dict_AddNumber (smask, "Height", (HPDF_UINT)height); ret += HPDF_Dict_AddName (smask, "ColorSpace", "DeviceGray"); ret += HPDF_Dict_AddNumber (smask, "BitsPerComponent", (HPDF_UINT)bit_depth); if (ret != HPDF_OK) { HPDF_Dict_Free(smask); ret = HPDF_INVALID_PNG_IMAGE; goto Exit; } smask_data = HPDF_GetMem(image->mmgr, width * height); if (!smask_data) { HPDF_Dict_Free(smask); ret = HPDF_FAILD_TO_ALLOC_MEM; goto Exit; } if (ReadTransparentPaletteData(image, png_ptr, info_ptr, smask_data, trans, num_trans) != HPDF_OK) { HPDF_FreeMem(image->mmgr, smask_data); HPDF_Dict_Free(smask); ret = HPDF_INVALID_PNG_IMAGE; goto Exit; } if (HPDF_Stream_Write(smask->stream, smask_data, width * height) != HPDF_OK) { HPDF_FreeMem(image->mmgr, smask_data); HPDF_Dict_Free(smask); ret = HPDF_FILE_IO_ERROR; goto Exit; } HPDF_FreeMem(image->mmgr, smask_data); ret += CreatePallet(image, png_ptr, info_ptr); ret += HPDF_Dict_AddNumber (image, "Width", (HPDF_UINT)width); ret += HPDF_Dict_AddNumber (image, "Height", (HPDF_UINT)height); ret += HPDF_Dict_AddNumber (image, "BitsPerComponent", (HPDF_UINT)bit_depth); ret += HPDF_Dict_Add (image, "SMask", smask); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return HPDF_OK; } no_transparent_color_in_palette: /* read images with alpha channel right away we have to do this because image transparent mask must be added to the Xref */ if (xref && PNG_COLOR_MASK_ALPHA & color_type) { HPDF_Dict smask; png_bytep smask_data; smask = HPDF_DictStream_New (image->mmgr, xref); if (!smask) { ret = HPDF_FAILD_TO_ALLOC_MEM; goto Exit; } smask->header.obj_class |= HPDF_OSUBCLASS_XOBJECT; ret = HPDF_Dict_AddName (smask, "Type", "XObject"); ret += HPDF_Dict_AddName (smask, "Subtype", "Image"); ret += HPDF_Dict_AddNumber (smask, "Width", (HPDF_UINT)width); ret += HPDF_Dict_AddNumber (smask, "Height", (HPDF_UINT)height); ret += HPDF_Dict_AddName (smask, "ColorSpace", "DeviceGray"); ret += HPDF_Dict_AddNumber (smask, "BitsPerComponent", (HPDF_UINT)bit_depth); if (ret != HPDF_OK) { HPDF_Dict_Free(smask); ret = HPDF_INVALID_PNG_IMAGE; goto Exit; } smask_data = HPDF_GetMem(image->mmgr, width * height); if (!smask_data) { HPDF_Dict_Free(smask); ret = HPDF_FAILD_TO_ALLOC_MEM; goto Exit; } if (ReadTransparentPngData(image, png_ptr, info_ptr, smask_data) != HPDF_OK) { HPDF_FreeMem(image->mmgr, smask_data); HPDF_Dict_Free(smask); ret = HPDF_INVALID_PNG_IMAGE; goto Exit; } if (HPDF_Stream_Write(smask->stream, smask_data, width * height) != HPDF_OK) { HPDF_FreeMem(image->mmgr, smask_data); HPDF_Dict_Free(smask); ret = HPDF_FILE_IO_ERROR; goto Exit; } HPDF_FreeMem(image->mmgr, smask_data); if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { ret += HPDF_Dict_AddName (image, "ColorSpace", "DeviceGray"); } else { ret += HPDF_Dict_AddName (image, "ColorSpace", "DeviceRGB"); } ret += HPDF_Dict_AddNumber (image, "Width", (HPDF_UINT)width); ret += HPDF_Dict_AddNumber (image, "Height", (HPDF_UINT)height); ret += HPDF_Dict_AddNumber (image, "BitsPerComponent", (HPDF_UINT)bit_depth); ret += HPDF_Dict_Add (image, "SMask", smask); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return HPDF_OK; } /* if the image has color palette, copy the pallet of the image to * create color map. */ if (color_type == PNG_COLOR_TYPE_PALETTE) ret = CreatePallet(image, png_ptr, info_ptr); else if (color_type == PNG_COLOR_TYPE_GRAY) ret = HPDF_Dict_AddName (image, "ColorSpace", "DeviceGray"); else ret = HPDF_Dict_AddName (image, "ColorSpace", "DeviceRGB"); if (ret != HPDF_OK) goto Exit; /* read image-data * if the image is interlaced, read whole image at once. * if delayed_loading is HPDF_TRUE, the data does not load this phase. */ if (delayed_loading) { image->before_write_fn = PngBeforeWrite; image->after_write_fn = PngAfterWrite; } else { if (png_get_interlace_type(png_ptr, info_ptr) != PNG_INTERLACE_NONE) ret = ReadPngData_Interlaced(image, png_ptr, info_ptr); else ret = ReadPngData(image, png_ptr, info_ptr); if (ret != HPDF_OK) goto Exit; } /* setting the info of the image. */ if (HPDF_Dict_AddNumber (image, "Width", (HPDF_UINT)width) != HPDF_OK) goto Exit; if (HPDF_Dict_AddNumber (image, "Height", (HPDF_UINT)height) != HPDF_OK) goto Exit; if (HPDF_Dict_AddNumber (image, "BitsPerComponent", (HPDF_UINT)bit_depth) != HPDF_OK) goto Exit; /* clean up */ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return HPDF_OK; Exit: png_destroy_read_struct(&png_ptr, &info_ptr, NULL); if (ret != HPDF_OK) { return ret; } return image->error->error_no; }
pngquant_error rwpng_read_image24_libpng(FILE *infile, png24_image *mainprog_ptr) { png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_size_t rowbytes; int color_type, bit_depth; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, mainprog_ptr, rwpng_error_handler, NULL); if (!png_ptr) { return PNG_OUT_OF_MEMORY_ERROR; /* out of memory */ } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); return PNG_OUT_OF_MEMORY_ERROR; /* out of memory */ } /* setjmp() must be called in every function that calls a non-trivial * libpng function */ if (setjmp(mainprog_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return LIBPNG_FATAL_ERROR; /* fatal libpng error (via longjmp()) */ } struct rwpng_read_data read_data = {infile, 0}; png_set_read_fn(png_ptr, &read_data, user_read_data); png_read_info(png_ptr, info_ptr); /* read all PNG info up to image data */ /* alternatively, could make separate calls to png_get_image_width(), * etc., but want bit_depth and color_type for later [don't care about * compression_type and filter_type => NULLs] */ png_get_IHDR(png_ptr, info_ptr, &mainprog_ptr->width, &mainprog_ptr->height, &bit_depth, &color_type, NULL, NULL, NULL); /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits, * transparency chunks to full alpha channel; strip 16-bit-per-sample * images to 8 bits per sample; and convert grayscale to RGB[A] */ /* GRR TO DO: preserve all safe-to-copy ancillary PNG chunks */ if (!(color_type & PNG_COLOR_MASK_ALPHA)) { #ifdef PNG_READ_FILLER_SUPPORTED png_set_expand(png_ptr); png_set_filler(png_ptr, 65535L, PNG_FILLER_AFTER); #else fprintf(stderr, "pngquant readpng: image is neither RGBA nor GA\n"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); mainprog_ptr->retval = 26; return mainprog_ptr->retval; #endif } /* if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(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); /* get and save the gamma info (if any) for writing */ double gamma; mainprog_ptr->gamma = png_get_gAMA(png_ptr, info_ptr, &gamma) ? gamma : 0.45455; png_set_interlace_handling(png_ptr); /* all transformations have been registered; now update info_ptr data, * get rowbytes and channels, and allocate image memory */ png_read_update_info(png_ptr, info_ptr); rowbytes = png_get_rowbytes(png_ptr, info_ptr); if ((mainprog_ptr->rgba_data = malloc(rowbytes*mainprog_ptr->height)) == NULL) { fprintf(stderr, "pngquant readpng: unable to allocate image data\n"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return PNG_OUT_OF_MEMORY_ERROR; } png_bytepp row_pointers = rwpng_create_row_pointers(info_ptr, png_ptr, mainprog_ptr->rgba_data, mainprog_ptr->height, 0); /* now we can go ahead and just read the whole image */ png_read_image(png_ptr, row_pointers); /* and we're done! (png_read_end() can be omitted if no processing of * post-IDAT text/time/etc. is desired) */ png_read_end(png_ptr, NULL); #if USE_LCMS if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) { png_uint_32 ProfileLen; png_bytep ProfileData; int Compression; png_charp ProfileName; png_get_iCCP(png_ptr, info_ptr, &ProfileName, &Compression, &ProfileData, &ProfileLen); cmsHPROFILE hInProfile = cmsOpenProfileFromMem(ProfileData, ProfileLen); cmsHPROFILE hOutProfile = cmsCreate_sRGBProfile(); cmsHTRANSFORM hTransform = cmsCreateTransform(hInProfile, TYPE_RGBA_8, hOutProfile, TYPE_RGBA_8, INTENT_PERCEPTUAL, 0); // suprisingly, using the same input and output works cmsDoTransform(hTransform, mainprog_ptr->rgba_data, mainprog_ptr->rgba_data, mainprog_ptr->height * mainprog_ptr->width); cmsDeleteTransform(hTransform); cmsCloseProfile(hOutProfile); cmsCloseProfile(hInProfile); } #endif png_destroy_read_struct(&png_ptr, &info_ptr, NULL); mainprog_ptr->file_size = read_data.bytes_read; mainprog_ptr->row_pointers = (unsigned char **)row_pointers; return SUCCESS; }
// // Reads the image // void PNGReader::read(ImageFile * image) { volatile unsigned char ** volatile rowPointers = NULL; png_struct * pngPtr = NULL; png_info * infoPtr = NULL; byte * data = NULL; try { int colorType, bitDepth; bool hasAlpha = false; uint bytesPerElement; ImageFormat format; unsigned long w, h; unsigned rowbytes; // Initialize the PNG library pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, pngErrorFunc, pngWarningFunc); if (unlikely(!pngPtr)) throw Exception(QString("%1: png_create_read_struct() failed").arg(m_File.fileName())); // Initialize the PNG info struct infoPtr = png_create_info_struct(pngPtr); if (unlikely(!infoPtr)) throw Exception(QString("%1: png_create_info_struct() failed").arg(m_File.fileName())); // Setup error handler if (unlikely(setjmp(png_jmpbuf(pngPtr)) != 0)) throw Exception(QString("%1: PNG decompression failed").arg(m_File.fileName())); // Setup file reading png_set_read_fn(pngPtr, &m_File, pngReadFunc); png_set_sig_bytes(pngPtr, 8); png_read_info(pngPtr, infoPtr); png_get_IHDR(pngPtr, infoPtr, &w, &h, &bitDepth, &colorType, NULL, NULL, NULL); // Setup 16 bit -> 8 bit conversion if (bitDepth > 8) png_set_strip_16(pngPtr); // Translate transparency to alpha channel if (png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(pngPtr); hasAlpha = true; } // Setup gamma correction double gamma; if (png_get_gAMA(pngPtr, infoPtr, &gamma)) png_set_gamma(pngPtr, 2.2, gamma); else png_set_gamma(pngPtr, 2.2, 0.45455); // We want at least 8-bit if (bitDepth < 8) { if ((colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA)) png_set_gray_1_2_4_to_8(pngPtr); else png_set_packing(pngPtr); } // Convert paletted images to RGB if (colorType == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(pngPtr); colorType = hasAlpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB; } // Convert gray/alpha images to RGB if (colorType == PNG_COLOR_TYPE_GRAY_ALPHA || (colorType == PNG_COLOR_TYPE_GRAY && hasAlpha)) { png_set_gray_to_rgb(pngPtr); colorType = PNG_COLOR_TYPE_RGB_ALPHA; } // Add dummy alpha channel for RGB images if (colorType == PNG_COLOR_TYPE_RGB && !hasAlpha) { png_set_filler(pngPtr, 0xFF, PNG_FILLER_BEFORE); hasAlpha = true; } else if (colorType == PNG_COLOR_TYPE_RGB_ALPHA) hasAlpha = true; // Select pixel format switch (colorType) { case PNG_COLOR_TYPE_PALETTE: case PNG_COLOR_TYPE_GRAY_ALPHA: Q_ASSERT(false); // Should be handled in the code above break; case PNG_COLOR_TYPE_GRAY: bytesPerElement = 1; format = R8_UNORM; break; default: Q_ASSERT(hasAlpha); // Should be handled in the code above bytesPerElement = 4; format = RGBA8_UNORM; break; } // Re-configure PNG reading to include configured conversions png_read_update_info(pngPtr, infoPtr); rowbytes = png_get_rowbytes(pngPtr, infoPtr); // Set basic image info setImageSize(image, w, h); setImageDepth(image, 0); setImageMipLevels(image, 1); setImageFaces(image, 0); setImageFormat(image, format); setImageElementSize(image, bytesPerElement); // Allocate memory for image data data = new byte[w * h * bytesPerElement]; if (unlikely(!data)) throw Exception("Out of memory."); // Allocate array of row pointers rowPointers = new volatile unsigned char * [h]; for (unsigned j = 0; j < h; j++) rowPointers[j] = data + j * rowbytes; // Read the image png_read_image(pngPtr, (png_byte **)rowPointers); // Store image information appendImageLevelData(image, data); data = NULL; // Free memory png_destroy_read_struct(&pngPtr, &infoPtr, NULL); pngPtr = NULL; } catch (...) { delete[] rowPointers; delete[] data; if (pngPtr) { if (infoPtr) png_destroy_read_struct(&pngPtr, &infoPtr, NULL); else png_destroy_read_struct(&pngPtr, NULL, NULL); } throw; } delete[] rowPointers; }
PyObject* _png_module::_read_png(const Py::Object& py_fileobj, const bool float_result) { png_byte header[8]; // 8 is the maximum size that can be checked FILE* fp = NULL; bool close_file = false; #if PY3K int fd = PyObject_AsFileDescriptor(py_fileobj.ptr()); PyErr_Clear(); #endif if (py_fileobj.isString()) { std::string fileName = Py::String(py_fileobj); const char *file_name = fileName.c_str(); if ((fp = fopen(file_name, "rb")) == NULL) { throw Py::RuntimeError( Printf("Could not open file %s for reading", file_name).str()); } close_file = true; } #if PY3K else if (fd != -1) { fp = fdopen(fd, "r"); } #else else if (PyFile_CheckExact(py_fileobj.ptr())) { fp = PyFile_AsFile(py_fileobj.ptr()); } #endif else { PyObject* read_method = PyObject_GetAttrString(py_fileobj.ptr(), "read"); if (!(read_method && PyCallable_Check(read_method))) { Py_XDECREF(read_method); throw Py::TypeError("Object does not appear to be a 8-bit string path or a Python file-like object"); } Py_XDECREF(read_method); } if (fp) { if (fread(header, 1, 8, fp) != 8) { throw Py::RuntimeError( "_image_module::readpng: error reading PNG header"); } } else { _read_png_data(py_fileobj.ptr(), header, 8); } if (png_sig_cmp(header, 0, 8)) { throw Py::RuntimeError( "_image_module::readpng: file not recognized as a PNG file"); } /* initialize stuff */ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { throw Py::RuntimeError( "_image_module::readpng: png_create_read_struct failed"); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { throw Py::RuntimeError( "_image_module::readpng: png_create_info_struct failed"); } if (setjmp(png_jmpbuf(png_ptr))) { throw Py::RuntimeError( "_image_module::readpng: error during init_io"); } if (fp) { png_init_io(png_ptr, fp); } else { png_set_read_fn(png_ptr, (void*)py_fileobj.ptr(), &read_png_data); } png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); png_uint_32 width = png_get_image_width(png_ptr, info_ptr); png_uint_32 height = png_get_image_height(png_ptr, info_ptr); int bit_depth = png_get_bit_depth(png_ptr, info_ptr); // Unpack 1, 2, and 4-bit images if (bit_depth < 8) png_set_packing(png_ptr); // If sig bits are set, shift data png_color_8p sig_bit; if ((png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_PALETTE) && png_get_sBIT(png_ptr, info_ptr, &sig_bit)) { png_set_shift(png_ptr, sig_bit); } // Convert big endian to little if (bit_depth == 16) { png_set_swap(png_ptr); } // Convert palletes to full RGB if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } // If there's an alpha channel convert gray to RGB if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); } png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); /* read file */ if (setjmp(png_jmpbuf(png_ptr))) { throw Py::RuntimeError( "_image_module::readpng: error during read_image"); } png_bytep *row_pointers = new png_bytep[height]; png_uint_32 row; for (row = 0; row < height; row++) { row_pointers[row] = new png_byte[png_get_rowbytes(png_ptr,info_ptr)]; } png_read_image(png_ptr, row_pointers); npy_intp dimensions[3]; dimensions[0] = height; //numrows dimensions[1] = width; //numcols if (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_ALPHA) { dimensions[2] = 4; //RGBA images } else if (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_COLOR) { dimensions[2] = 3; //RGB images } else { dimensions[2] = 1; //Greyscale images } //For gray, return an x by y array, not an x by y by 1 int num_dims = (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_COLOR) ? 3 : 2; PyArrayObject *A = NULL; if (float_result) { double max_value = (1 << bit_depth) - 1; PyArrayObject *A = (PyArrayObject *) PyArray_SimpleNew( num_dims, dimensions, PyArray_FLOAT); if (A == NULL) { throw Py::MemoryError("Could not allocate image array"); } for (png_uint_32 y = 0; y < height; y++) { png_byte* row = row_pointers[y]; for (png_uint_32 x = 0; x < width; x++) { size_t offset = y * A->strides[0] + x * A->strides[1]; if (bit_depth == 16) { png_uint_16* ptr = &reinterpret_cast<png_uint_16*>(row)[x * dimensions[2]]; for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) { *(float*)(A->data + offset + p*A->strides[2]) = (float)(ptr[p]) / max_value; } } else { png_byte* ptr = &(row[x * dimensions[2]]); for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) { *(float*)(A->data + offset + p*A->strides[2]) = (float)(ptr[p]) / max_value; } } } } } else { A = (PyArrayObject *) PyArray_SimpleNew(num_dims, dimensions, NPY_UBYTE); if (A == NULL) { throw Py::MemoryError("Could not allocate image array"); } for (png_uint_32 y = 0; y < height; y++) { png_byte* row = row_pointers[y]; for (png_uint_32 x = 0; x < width; x++) { size_t offset = y * A->strides[0] + x * A->strides[1]; if (bit_depth == 16) { png_uint_16* ptr = &reinterpret_cast<png_uint_16*>(row)[x * dimensions[2]]; for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) { *(png_byte*)(A->data + offset + p*A->strides[2]) = ptr[p] >> 8; } } else { png_byte* ptr = &(row[x * dimensions[2]]); for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) { *(png_byte*)(A->data + offset + p*A->strides[2]) = ptr[p]; } } } }
static GF_Err PNG_ProcessData(GF_MediaDecoder *ifcg, char *inBuffer, u32 inBufferLength, u16 ES_ID, char *outBuffer, u32 *outBufferLength, u8 PaddingBits, u32 mmlevel) { png_struct *png_ptr; png_info *info_ptr; png_byte **rows; u32 i, stride; PNGCTX(); if ((inBufferLength<8) || png_sig_cmp(inBuffer, 0, 8) ) return GF_NON_COMPLIANT_BITSTREAM; ctx->in_data = inBuffer; ctx->in_length = inBufferLength; ctx->current_pos = 0; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) ctx, NULL, NULL); if (!png_ptr) return GF_IO_ERR; info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return GF_IO_ERR; } if (setjmp(png_ptr->jmpbuf)) { png_destroy_info_struct(png_ptr,(png_infopp) & info_ptr); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return GF_IO_ERR; } png_set_read_fn(png_ptr, ctx, (png_rw_ptr) user_read_data); png_set_error_fn(png_ptr, ctx, (png_error_ptr) user_error_fn, NULL); png_read_info(png_ptr, info_ptr); /*unpaletize*/ if (info_ptr->color_type==PNG_COLOR_TYPE_PALETTE) { png_set_expand(png_ptr); png_read_update_info(png_ptr, info_ptr); } if (info_ptr->num_trans) { png_set_tRNS_to_alpha(png_ptr); png_read_update_info(png_ptr, info_ptr); } ctx->BPP = info_ptr->pixel_depth / 8; ctx->width = info_ptr->width; ctx->height = info_ptr->height; switch (ctx->BPP) { case 1: ctx->pixel_format = GF_PIXEL_GREYSCALE; break; case 2: ctx->pixel_format = GF_PIXEL_ALPHAGREY; break; case 3: ctx->pixel_format = GF_PIXEL_RGB_24; break; case 4: ctx->pixel_format = GF_PIXEL_RGBA; break; } /*new cfg, reset*/ if (ctx->out_size != ctx->width * ctx->height * ctx->BPP) { ctx->out_size = ctx->width * ctx->height * ctx->BPP; *outBufferLength = ctx->out_size; png_destroy_info_struct(png_ptr,(png_infopp) & info_ptr); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return GF_BUFFER_TOO_SMALL; } /*read*/ stride = png_get_rowbytes(png_ptr, info_ptr); rows = (png_bytepp) malloc(sizeof(png_bytep) * ctx->height); for (i=0; i<ctx->height; i++) { rows[i] = outBuffer + i*stride; } png_read_image(png_ptr, rows); png_read_end(png_ptr, NULL); free(rows); png_destroy_info_struct(png_ptr,(png_infopp) & info_ptr); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); *outBufferLength = ctx->out_size; return GF_OK; }
/* Alternate create PNG structure for reading, and allocate any memory * needed. */ png_structp PNGAPI png_create_read_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn) { #endif /* PNG_USER_MEM_SUPPORTED */ #ifdef PNG_SETJMP_SUPPORTED volatile #endif png_structp png_ptr; #ifdef PNG_SETJMP_SUPPORTED #ifdef USE_FAR_KEYWORD jmp_buf jmpbuf; #endif #endif int i; png_debug(1, "in png_create_read_struct"); #ifdef PNG_USER_MEM_SUPPORTED png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG, (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr); #else png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); #endif if (png_ptr == NULL) return (NULL); /* Added at libpng-1.2.6 */ #ifdef PNG_USER_LIMITS_SUPPORTED png_ptr->user_width_max = PNG_USER_WIDTH_MAX; png_ptr->user_height_max = PNG_USER_HEIGHT_MAX; # ifdef PNG_USER_CHUNK_CACHE_MAX /* Added at libpng-1.2.43 and 1.4.0 */ png_ptr->user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX; # endif # ifdef PNG_SET_USER_CHUNK_MALLOC_MAX /* Added at libpng-1.2.43 and 1.4.1 */ png_ptr->user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX; # endif #endif #ifdef PNG_SETJMP_SUPPORTED #ifdef USE_FAR_KEYWORD if (setjmp(jmpbuf)) #else if (setjmp(png_ptr->jmpbuf)) #endif { png_free(png_ptr, png_ptr->zbuf); png_ptr->zbuf = NULL; #ifdef PNG_USER_MEM_SUPPORTED png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn, (png_voidp)mem_ptr); #else png_destroy_struct((png_voidp)png_ptr); #endif return (NULL); } #ifdef USE_FAR_KEYWORD png_memcpy(png_ptr->jmpbuf, jmpbuf, png_sizeof(jmp_buf)); #endif #endif /* PNG_SETJMP_SUPPORTED */ #ifdef PNG_USER_MEM_SUPPORTED png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn); #endif png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn); if (user_png_ver) { i = 0; do { if (user_png_ver[i] != png_libpng_ver[i]) png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; } while (png_libpng_ver[i++]); } else png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) { /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so * we must recompile any applications that use any older library version. * For versions after libpng 1.0, we will be compatible, so we need * only check the first digit. */ if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) || (user_png_ver[0] == '0' && user_png_ver[2] < '9')) { #if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) char msg[80]; if (user_png_ver) { png_snprintf(msg, 80, "Application was compiled with png.h from libpng-%.20s", user_png_ver); png_warning(png_ptr, msg); } png_snprintf(msg, 80, "Application is running with png.c from libpng-%.20s", png_libpng_ver); png_warning(png_ptr, msg); #endif #ifdef PNG_ERROR_NUMBERS_SUPPORTED png_ptr->flags = 0; #endif png_error(png_ptr, "Incompatible libpng version in application and library"); } } /* Initialize zbuf - compression buffer */ png_ptr->zbuf_size = PNG_ZBUF_SIZE; png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, (png_uint_32)png_ptr->zbuf_size); png_ptr->zstream.zalloc = png_zalloc; png_ptr->zstream.zfree = png_zfree; png_ptr->zstream.opaque = (voidpf)png_ptr; switch (inflateInit(&png_ptr->zstream)) { case Z_OK: /* Do nothing */ break; case Z_MEM_ERROR: case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory error"); break; case Z_VERSION_ERROR: png_error(png_ptr, "zlib version error"); break; default: png_error(png_ptr, "Unknown zlib error"); } png_ptr->zstream.next_out = png_ptr->zbuf; png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; png_set_read_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL); #ifdef PNG_SETJMP_SUPPORTED /* Applications that neglect to set up their own setjmp() and then encounter a png_error() will longjmp here. Since the jmpbuf is then meaningless we abort instead of returning. */ #ifdef USE_FAR_KEYWORD if (setjmp(jmpbuf)) PNG_ABORT(); png_memcpy(png_ptr->jmpbuf, jmpbuf, png_sizeof(jmp_buf)); #else if (setjmp(png_ptr->jmpbuf)) PNG_ABORT(); #endif #endif /* PNG_SETJMP_SUPPORTED */ return (png_ptr); }
void LoadImage (const char *filename, unsigned char **pic, int *width, int *height) { png_byte** row_pointers; unsigned char *fbuffer = NULL; png_bytep p_fbuffer; int nLen = g_FileSystemTable.m_pfnLoadFile( (char *)filename, (void **)&fbuffer, 0 ); if (nLen == -1) return; p_fbuffer = fbuffer; // the reading glue // http://www.libpng.org/pub/png/libpng-manual.html png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, png_voidp_NULL, user_error_fn, user_warning_fn); if (!png_ptr) { g_FuncTable.m_pfnSysPrintf ("libpng error: png_create_read_struct\n"); return; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); g_FuncTable.m_pfnSysPrintf ("libpng error: png_create_info_struct (info_ptr)\n"); return; } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); g_FuncTable.m_pfnSysPrintf ("libpng error: png_create_info_struct (end_info)\n"); return; } // configure the read function png_set_read_fn(png_ptr, (voidp)&p_fbuffer, (png_rw_ptr)&user_read_data); if (setjmp(png_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); if (*pic) { g_free(*pic); free(row_pointers); } return; } png_read_info(png_ptr, info_ptr); int bit_depth = png_get_bit_depth(png_ptr, info_ptr); int color_type = png_get_color_type(png_ptr, info_ptr); // we want to treat all images the same way // The following code transforms grayscale images of less than 8 to 8 bits, // changes paletted images to RGB, and adds a full alpha channel if there is // transparency information in a tRNS chunk. 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_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); if ( ! ( color_type & PNG_COLOR_MASK_ALPHA ) ) { // Set the background color to draw transparent and alpha images over. 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); // Add alpha byte after each RGB triplet png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); } // read the sucker in one chunk png_read_update_info(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); *width = png_get_image_width(png_ptr, info_ptr); *height = png_get_image_height(png_ptr, info_ptr); // allocate the pixel buffer, and the row pointers int size = (*width)*(*height)*4; // still have to use that g_malloc heresy *pic = (unsigned char *)g_malloc(size); row_pointers = (png_byte**) malloc((*height) * sizeof(png_byte*)); int i; for(i = 0; i < (*height); i++) row_pointers[i] = (png_byte*)(*pic) + i * 4 * (*width); // actual read png_read_image(png_ptr, row_pointers); /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); /* free up the memory structure */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); free(row_pointers); g_FileSystemTable.m_pfnFreeFile (fbuffer); }
void ossimPngReader::restart() { if ( m_str ) { // Destroy the existing memory associated with png structs. if (m_pngReadPtr && m_pngReadInfoPtr) { png_destroy_read_struct(&m_pngReadPtr, &m_pngReadInfoPtr, NULL); } m_pngReadPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); m_pngReadInfoPtr = png_create_info_struct(m_pngReadPtr); if ( setjmp( png_jmpbuf(m_pngReadPtr) ) ) { ossimNotify(ossimNotifyLevel_WARN) << "Error while reading. File corrupted? " << theImageFile << std::endl; return; } // Reset the file pointer. m_str->seekg( m_restartPosition, std::ios_base::beg ); //--- // Pass the static read method to libpng to allow us to use our // c++ stream instead of doing "png_init_io (pp, ...);" with // c stream. //--- png_set_read_fn( m_pngReadPtr, (png_voidp)m_str, (png_rw_ptr)&ossimPngReader::pngReadData ); //--- // Note we won't do png_set_sig_bytes(png_ptr, 8) here because we are not // rechecking for png signature. //--- png_read_info(m_pngReadPtr, m_pngReadInfoPtr); //--- // If png_set_expand used: // Expand data to 24-bit RGB, or 8-bit grayscale, // with alpha if available. //--- bool expandFlag = false; if ( m_pngColorType == PNG_COLOR_TYPE_PALETTE ) { expandFlag = true; } if ( (m_pngColorType == PNG_COLOR_TYPE_GRAY) && (m_bitDepth < 8) ) { expandFlag = true; } if ( png_get_valid(m_pngReadPtr, m_pngReadInfoPtr, PNG_INFO_tRNS) ) { expandFlag = true; } //--- // If png_set_packing used: // Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ //--- bool packingFlag = false; if ( (m_bitDepth < 8) && (m_pngColorType == PNG_COLOR_TYPE_GRAY) ) { packingFlag = true; } if (expandFlag) { png_set_expand(m_pngReadPtr); } if (packingFlag) { png_set_packing(m_pngReadPtr); } // Gamma correction. // ossim_float64 gamma; // if (png_get_gAMA(m_pngReadPtr, m_pngReadInfoPtr, &gamma)) // { // png_set_gamma(m_pngReadPtr, display_exponent, gamma); // } //--- // Turn on interlace handling... libpng returns just 1 (ie single pass) // if the image is not interlaced //--- png_set_interlace_handling (m_pngReadPtr); //--- // Update the info structures after the transformations take effect //--- png_read_update_info (m_pngReadPtr, m_pngReadInfoPtr); // We're back on row 0 or first line. m_currentRow = 0; } }
bool CCImage::_initWithPngData(void * pData, int nDatalen) { bool bRet = false; png_byte header[8] = {0}; png_structp png_ptr = 0; png_infop info_ptr = 0; unsigned char * pImateData = 0; do { // png header len is 8 bytes CC_BREAK_IF(nDatalen < 8); // check the data is png or not memcpy(header, pData, 8); CC_BREAK_IF(png_sig_cmp(header, 0, 8)); // init png_struct png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); CC_BREAK_IF(! png_ptr); // init png_info info_ptr = png_create_info_struct(png_ptr); CC_BREAK_IF(!info_ptr || setjmp(png_jmpbuf(png_ptr))); // set the read call back function tImageSource imageSource; imageSource.data = (unsigned char*)pData; imageSource.size = nDatalen; imageSource.offset = 0; png_set_read_fn(png_ptr, &imageSource, pngReadCallback); // read png // PNG_TRANSFORM_EXPAND: perform set_expand() // PNG_TRANSFORM_PACKING: expand 1, 2 and 4-bit samples to bytes // PNG_TRANSFORM_STRIP_16: strip 16-bit samples to 8 bits // PNG_TRANSFORM_GRAY_TO_RGB: expand grayscale samples to RGB (or GA to RGBA) png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_GRAY_TO_RGB, 0); int color_type = 0; png_uint_32 nWidth = 0; png_uint_32 nHeight = 0; int nBitsPerComponent = 0; png_get_IHDR(png_ptr, info_ptr, &nWidth, &nHeight, &nBitsPerComponent, &color_type, 0, 0, 0); // init image info m_bPreMulti = true; m_bHasAlpha = ( info_ptr->color_type & PNG_COLOR_MASK_ALPHA ) ? true : false; // allocate memory and read data int bytesPerComponent = 3; if (m_bHasAlpha) { bytesPerComponent = 4; } pImateData = new unsigned char[nHeight * nWidth * bytesPerComponent]; CC_BREAK_IF(! pImateData); png_bytep * rowPointers = png_get_rows(png_ptr, info_ptr); // copy data to image info int bytesPerRow = nWidth * bytesPerComponent; if(m_bHasAlpha) { unsigned int *tmp = (unsigned int *)pImateData; for(unsigned int i = 0; i < nHeight; i++) { for(int j = 0; j < bytesPerRow; j += 4) { *tmp++ = CC_RGB_PREMULTIPLY_APLHA( rowPointers[i][j], rowPointers[i][j + 1], rowPointers[i][j + 2], rowPointers[i][j + 3] ); } } } else { for (unsigned int j = 0; j < nHeight; ++j) { memcpy(pImateData + j * bytesPerRow, rowPointers[j], bytesPerRow); } } m_nBitsPerComponent = nBitsPerComponent; m_nHeight = (short)nHeight; m_nWidth = (short)nWidth; m_pData = pImateData; pImateData = 0; bRet = true; } while (0); CC_SAFE_DELETE_ARRAY(pImateData); if (png_ptr) { png_destroy_read_struct(&png_ptr, (info_ptr) ? &info_ptr : 0, 0); } return bRet; }
int PngDecoder::validate() { if (png_sig_cmp((png_bytep)buf->data(), 0, PNG_HEADER_SIZE)) { std::cout << "[PngDecoder] error: %s is not a PNG." << std::endl; return -1; } buf->drain(PNG_HEADER_SIZE); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { std::cout << "[PngDecoder] error: png_create_read_struct returned 0." << std::endl; return -1; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { std::cout << "[PngDecoder] error: png_create_info_struct returned 0." << std::endl; png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return -1; } end_info = png_create_info_struct(png_ptr); if (!end_info) { std::cout << "[PngDecoder] error: png_create_info_struct returned 0." << std::endl; png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); return -1; } if (setjmp(png_jmpbuf(png_ptr))) { std::cout << "[PngDecoder] error from libpng" << std::endl; png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return -1; } png_set_read_fn(png_ptr, buf, pngDecoderReadFunction); png_set_sig_bytes(png_ptr, PNG_HEADER_SIZE); png_read_info(png_ptr, info_ptr); png_set_expand(png_ptr); png_set_strip_16(png_ptr); png_set_gray_to_rgb(png_ptr); png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER); png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); imgInfo.width = png_get_image_width(png_ptr, info_ptr); imgInfo.height = png_get_image_height(png_ptr, info_ptr); imgInfo.color_type = png_get_color_type(png_ptr, info_ptr); imgInfo.channels = png_get_channels(png_ptr, info_ptr); imgInfo.bit_depth = png_get_bit_depth(png_ptr, info_ptr); imgInfo.interlance_type = png_get_interlace_type(png_ptr, info_ptr); imgInfo.rowbytes = png_get_rowbytes(png_ptr, info_ptr); #ifdef _PNGDECODER_DEBUG std::cout << "[PngDecoder] Extracted w=" << imgInfo.width << " h=" << imgInfo.height << " color_type=" << imgInfo.color_type << " bit_depth="<< imgInfo.bit_depth << " rowbytes="<< imgInfo.rowbytes << " channels="<< imgInfo.channels << " interlance_type="<< imgInfo.interlance_type << std::endl; #endif if (imgInfo.bit_depth != 8) { std::cout << "[PngDecoder] error: Unsupported bit depth=" << imgInfo.bit_depth <<". Must be 8." << std::endl; return -1; } switch(imgInfo.color_type) { case PNG_COLOR_TYPE_RGB: imgInfo.format = GL_RGB; break; case PNG_COLOR_TYPE_RGB_ALPHA: imgInfo.format = GL_RGBA; break; case PNG_COLOR_TYPE_PALETTE: if (imgInfo.color_type & PNG_COLOR_MASK_ALPHA) { imgInfo.format = GL_RGBA; } else if (imgInfo.color_type & PNG_COLOR_MASK_COLOR) { imgInfo.format = GL_RGB; } break; default: std::cout << "[PngDecoder] error: unknown libpng color type=" << imgInfo.color_type << " rgb=" << PNG_COLOR_TYPE_RGB << " rgba=" << PNG_COLOR_TYPE_RGBA << " palette=" << PNG_COLOR_TYPE_PALETTE << std::endl; return -1; } return 0; }
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); 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); } 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; }
BMGError ReadPNGInfo( const char *filename, struct BMGImageStruct * volatile img ) { jmp_buf err_jmp; int error; FILE * volatile file = NULL; int BitDepth; int ColorType; int InterlaceType; unsigned char signature[8]; png_structp volatile png_ptr = NULL; png_infop volatile info_ptr = NULL; png_infop volatile end_info = NULL; png_uint_32 Width, Height; /* error handler */ error = setjmp( err_jmp ); if (error != 0) { if (end_info != NULL) png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info); else if (info_ptr != NULL) png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, NULL); else if (png_ptr != NULL) png_destroy_read_struct((png_structp *) &png_ptr, NULL, NULL); if (img) FreeBMGImage(img); if (file) fclose(file); SetLastBMGError((BMGError) error); return (BMGError) error; } if ( img == NULL ) longjmp ( err_jmp, (int)errInvalidBMGImage ); file = fopen( filename, "rb" ); if ( !file || fread( signature, 1, 8, file ) != 8) longjmp ( err_jmp, (int)errFileOpen ); /* check the signature */ if ( png_sig_cmp( signature, 0, 8 ) != 0 ) longjmp( err_jmp, (int)errUnsupportedFileFormat ); /* create a pointer to the png read structure */ png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); if ( !png_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create a pointer to the png info structure */ info_ptr = png_create_info_struct( png_ptr ); if ( !info_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create a pointer to the png end-info structure */ end_info = png_create_info_struct(png_ptr); if (!end_info) longjmp( err_jmp, (int)errMemoryAllocation ); /* bamboozle the PNG longjmp buffer */ /*generic PNG error handler*/ /* error will always == 1 which == errLib */ // error = png_setjmp(png_ptr); error = setjmp( png_jmpbuf( png_ptr ) ); if ( error > 0 ) longjmp( err_jmp, error ); /* set function pointers in the PNG library, for read callbacks */ png_set_read_fn(png_ptr, (png_voidp) file, user_read_data); /*let the read functions know that we have already read the 1st 8 bytes */ png_set_sig_bytes( png_ptr, 8 ); /* read all PNG data up to the image data */ png_read_info( png_ptr, info_ptr ); /* extract the data we need to form the HBITMAP from the PNG header */ png_get_IHDR( png_ptr, info_ptr, &Width, &Height, &BitDepth, &ColorType, &InterlaceType, NULL, NULL); img->width = (unsigned int) Width; img->height = (unsigned int) Height; img->bits_per_pixel = (unsigned char)32; img->scan_width = Width * 4; img->palette_size = (unsigned short)0; img->bytes_per_palette_entry = 4U; img->bits = NULL; png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info); fclose( file ); return BMG_OK; }
bool R9_ImgReadPNG( F9FILE file, r9Img* img ) { if(file==NULL || img==NULL) return false; R9_ImgDestroy(img); // check png sig const int headersize = 8; byte header[headersize]; if(file->Read( header, headersize) != headersize) return false; BOOL ispng = png_check_sig(header, headersize) != 0; if(!ispng) { elog::rnd() << "png sig failed" << std::endl; return false; } // create png structures png_structp png_ptr = png_create_read_struct_2( PNG_LIBPNG_VER_STRING, NULL, R9_ImgPNG_FatalError, R9_ImgPNG_Warning, NULL, R9_ImgPNG_Malloc, R9_ImgPNG_Free ); if(png_ptr==NULL) return false; png_infop info_ptr = png_create_info_struct(png_ptr); if(info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return false; } png_infop end_info = png_create_info_struct(png_ptr); if(end_info == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return false; } // set global file r9_imgpng_file = file; png_set_read_fn(png_ptr, NULL, R9_ImgPNG_ReadData); // read off the info on the image png_set_sig_bytes(png_ptr, headersize); png_read_info(png_ptr, info_ptr); png_uint_32 pngwidth; png_uint_32 pngheight; int32 pngbits; int32 pngpf; png_get_IHDR(png_ptr, info_ptr, &pngwidth, &pngheight, &pngbits, &pngpf, NULL, // interlace NULL, // compression_type NULL); // filter_type BOOL alpha = FALSE; img->m_width = pngwidth; img->m_height = pngheight; img->m_pf = R9_PF_RGB; assert(img->m_width!=0 && img->m_height!=0); // Strip off any 16 bit info if(pngbits==16) png_set_strip_16(png_ptr); // Expand a transparency channel into a full alpha channel... if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_expand(png_ptr); alpha = TRUE; } if( pngpf == PNG_COLOR_TYPE_RGB) { png_set_expand(png_ptr); img->m_pf = alpha ? R9_PF_ARGB : R9_PF_RGB; } else if( pngpf == PNG_COLOR_TYPE_RGB_ALPHA) { png_set_expand(png_ptr); img->m_pf = R9_PF_ARGB; } else { elog::rnd() << "png wrong color format" << std::endl; png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return false; } // Update the info pointer with the result of the transformations above... png_read_update_info(png_ptr, info_ptr); png_uint_32 rowbytes = png_get_rowbytes(png_ptr, info_ptr); if(img->m_pf==R9_PF_RGB) assert(rowbytes==img->m_width*3); else if(img->m_pf==R9_PF_RGB) assert(rowbytes==img->m_width*4); // create image R9_ImgCreate(img); // set up the row pointers... png_bytep* rowpointers = new png_bytep[img->m_height]; for(int i=0; i<img->m_height; i++) rowpointers[i] = img->m_data + (i*rowbytes); // read image png_read_image(png_ptr, rowpointers); // release png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); delete [] rowpointers; r9_imgpng_file = NULL; R9_ImgFlipRGB(img); // it was BGR, we want it RGB ! return true; }
unsigned char* LoadPNGJPGFromMemory(const unsigned char* buffer, int len, int* width, int* height) { const int number=8; // проверяем сигнатуру файла (первые number байт) if ( !png_check_sig((png_bytep)buffer, number) ) { // неизвестный формат return LoadJPGWithAlphaFromMemory(buffer, len, width, height); } // создаем внутреннюю структуру png для работы с файлом // последние параметры - структура, для функции обработки ошибок и варнинга (последн. 2 параметра) png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); // создаем структуру с информацией о файле png_infop info_ptr = png_create_info_struct(png_ptr); PNGBuffer pngBuffer; pngBuffer.data = (png_bytep)buffer; pngBuffer.position = 8; png_set_read_fn(png_ptr, (void*)&pngBuffer, PNGRead); // говорим библиотеке, что мы уже прочли number байт, когда проверяли сигнатуру png_set_sig_bytes(png_ptr, number); // читаем всю информацию о файле png_read_info(png_ptr, info_ptr); // Эта функция возвращает инфу из info_ptr png_uint_32 w = 0, h = 0; // размер картинки в пикселях int bit_depth = 0; // глубина цвета (одного из каналов, может быть 1, 2, 4, 8, 16) int color_type = 0; // описывает какие каналы присутствуют: // PNG_COLOR_TYPE_GRAY, PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, // PNG_COLOR_TYPE_RGB, PNG_COLOR_TYPE_RGB_ALPHA... // последние 3 параметра могут быть нулями и обозначают: тип фильтра, тип компрессии и тип смещения png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, 0, 0, 0); // png формат может содержать 16 бит на канал, но нам нужно только 8, поэтому сужаем канал if (bit_depth == 16) png_set_strip_16(png_ptr); // преобразуем файл если он содержит палитру в нормальный RGB if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8) png_set_palette_to_rgb(png_ptr); // если в грэйскейле меньше бит на канал чем 8, то конвертим к нормальному 8-битному //if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_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); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); double gamma = 0.0f; // если есть информация о гамме в файле, то устанавливаем на 2.2 if ( png_get_gAMA(png_ptr, info_ptr, &gamma) ) png_set_gamma(png_ptr, 2.2, gamma); // иначе ставим дефолтную гамму для файла в 0.45455 (good guess for GIF images on PCs) else png_set_gamma(png_ptr, 2.2, 0.45455); // после всех трансформаций, апдейтим информацию в библиотеке png_read_update_info(png_ptr, info_ptr); // опять получаем все размеры и параметры обновленной картинки png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, 0, 0, 0); // определяем кол-во байт нужных для того чтобы вместить строку png_uint_32 row_bytes = png_get_rowbytes(png_ptr, info_ptr); // теперь, мы можем выделить память чтобы вместить картинку png_byte* data = new png_byte[row_bytes * h]; // выделяем память, для указателей на каждую строку png_byte **row_pointers = new png_byte * [h]; // сопоставляем массив указателей на строчки, с выделенными в памяти (res) // т.к. изображение перевернутое, то указатели идут снизу вверх for (unsigned int i = 0; i < h; i++) row_pointers[i] = data + i * row_bytes; // все, читаем картинку png_read_image(png_ptr, row_pointers); // освобождаем память от указателей на строки delete []row_pointers; // освобождаем память выделенную для библиотеки libpng png_destroy_read_struct(&png_ptr, &info_ptr, 0); *width=w; *height=h; return data; }
bool R9_ImgReadHeaderPNG( F9FILE file, r9Img* img ) { if(file==NULL || img==NULL) return false; R9_ImgDestroy(img); // check png sig const int headersize = 8; byte header[headersize]; if(file->Read( header, headersize)!=headersize) return false; BOOL ispng = png_check_sig(header, headersize) != 0; if(!ispng) { elog::rnd() << "png sig failed" << std::endl; return false; } // create png structures png_structp png_ptr = png_create_read_struct_2( PNG_LIBPNG_VER_STRING, NULL, R9_ImgPNG_FatalError, R9_ImgPNG_Warning, NULL, R9_ImgPNG_Malloc, R9_ImgPNG_Free ); if(png_ptr==NULL) return false; png_infop info_ptr = png_create_info_struct(png_ptr); if(info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return false; } png_infop end_info = png_create_info_struct(png_ptr); if(end_info == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return false; } // set global file r9_imgpng_file = file; png_set_read_fn(png_ptr, NULL, R9_ImgPNG_ReadData); // read off the info on the image png_set_sig_bytes(png_ptr, headersize); png_read_info(png_ptr, info_ptr); png_uint_32 pngwidth; png_uint_32 pngheight; int32 pngbits; int32 pngpf; png_get_IHDR(png_ptr, info_ptr, &pngwidth, &pngheight, &pngbits, &pngpf, NULL, // interlace NULL, // compression_type NULL); // filter_type BOOL alpha = FALSE; img->m_width = pngwidth; img->m_height = pngheight; img->m_pf = R9_PF_RGB; // release png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); r9_imgpng_file = NULL; return true; }
/* Read a PNG file. You may want to return an error code if the read * fails (depending upon the failure). There are two "prototypes" given * here - one where we are given the filename, and we need to open the * file, and the other where we are given an open file (possibly with * some or all of the magic bytes read - see comments above). */ #ifdef open_file /* prototype 1 */ void read_png(char *file_name) /* We need to open the file */ { png_structp png_ptr; png_infop info_ptr; unsigned int sig_read = 0; png_uint_32 width, height; int bit_depth, color_type, interlace_type; FILE *fp; if ((fp = fopen(file_name, "rb")) == NULL) return (ERROR); #else no_open_file /* prototype 2 */ void read_png(FILE *fp, unsigned int sig_read) /* File is already open */ { png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int bit_depth, color_type, interlace_type; #endif no_open_file /* Only use one prototype! */ /* 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); if (png_ptr == NULL) { fclose(fp); return (ERROR); } /* 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, NULL, NULL); return (ERROR); } /* 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, NULL); fclose(fp); /* If we get here, we had a problem reading the file */ return (ERROR); } /* One of the following I/O initialization methods is REQUIRED */ #ifdef streams /* PNG file I/O method 1 */ /* Set up the input control if you are using standard C streams */ png_init_io(png_ptr, fp); #else no_streams /* PNG file I/O method 2 */ /* If you are using replacement read functions, instead of calling * png_init_io() here you would call: */ png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn); /* where user_io_ptr is a structure you want available to the callbacks */ #endif no_streams /* Use only one I/O method! */ /* If we have already read some of the signature */ png_set_sig_bytes(png_ptr, sig_read); #ifdef hilevel /* * If you have enough memory to read in the entire image at once, * and you need to specify only transforms that can be controlled * with one of the PNG_TRANSFORM_* bits (this presently excludes * quantizing, filling, setting background, and doing gamma * adjustment), then you can read the entire image (including * pixels) into the info structure with this call: */ png_read_png(png_ptr, info_ptr, png_transforms, NULL); #else /* 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, NULL, 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. * Use accurate scaling if it's available, otherwise just chop off the * low byte. */ #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED png_set_scale_16(png_ptr); #else png_set_strip_16(png_ptr); #endif /* 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) != 0) 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) != 0) 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); /* Some suggestions as to how to get a screen gamma value * * Note that screen gamma is the display_exponent, which includes * the CRT_exponent and any correction for viewing conditions */ if (/* We have a user-defined screen gamma value */) { screen_gamma = user-defined screen_gamma; } /* This is one way that applications share the same screen gamma value */ else if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL)
void LoadPNG( const char *name, byte **pic, int *width, int *height, int *numLayers, int *numMips, int *bits, byte alphaByte ) { int bit_depth; int color_type; png_uint_32 w; png_uint_32 h; unsigned int row; png_infop info; png_structp png; png_bytep *row_pointers; byte *data; byte *out; // load png ri.FS_ReadFile( name, ( void ** ) &data ); if ( !data ) { return; } png = png_create_read_struct( PNG_LIBPNG_VER_STRING, ( png_voidp ) nullptr, png_user_error_fn, png_user_warning_fn ); if ( !png ) { ri.Printf( PRINT_WARNING, "LoadPNG: png_create_write_struct() failed for (%s)\n", name ); ri.FS_FreeFile( data ); return; } // allocate/initialize the memory for image information. REQUIRED info = png_create_info_struct( png ); if ( !info ) { ri.Printf( PRINT_WARNING, "LoadPNG: png_create_info_struct() failed for (%s)\n", name ); ri.FS_FreeFile( data ); png_destroy_read_struct( &png, ( png_infopp ) nullptr, ( png_infopp ) nullptr ); return; } /* * Set error handling if you are using the setjmp/longjmp method (this is * the common 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 ) ) ) { // if we get here, we had a problem reading the file ri.Printf( PRINT_WARNING, "LoadPNG: first exception handler called for (%s)\n", name ); ri.FS_FreeFile( data ); png_destroy_read_struct( &png, ( png_infopp ) & info, ( png_infopp ) nullptr ); return; } png_set_read_fn( png, data, png_read_data ); png_set_sig_bytes( png, 0 ); // 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, info ); // get picture info png_get_IHDR( png, info, ( png_uint_32 * ) &w, ( png_uint_32 * ) &h, &bit_depth, &color_type, nullptr, nullptr, nullptr ); // tell libpng to strip 16 bit/color files down to 8 bits/color png_set_strip_16( png ); // expand paletted images to RGB triplets if ( color_type & PNG_COLOR_MASK_PALETTE ) { png_set_expand( png ); } // expand gray-scaled images to RGB triplets if ( !( color_type & PNG_COLOR_MASK_COLOR ) ) { png_set_gray_to_rgb( png ); } // expand grayscale images to the 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 ( png_get_valid( png, info, PNG_INFO_tRNS ) ) { png_set_tRNS_to_alpha( png ); } // if there is no alpha information, fill with alphaByte if ( !( color_type & PNG_COLOR_MASK_ALPHA ) ) { png_set_filler( png, alphaByte, PNG_FILLER_AFTER ); } // expand pictures with less than 8bpp to 8bpp if ( bit_depth < 8 ) { png_set_packing( png ); } png_set_interlace_handling( png ); // update structure with the above settings png_read_update_info( png, info ); // allocate the memory to hold the image *width = w; *height = h; *pic = out = ( byte * ) ri.Z_Malloc( w * h * 4 ); row_pointers = ( png_bytep * ) ri.Hunk_AllocateTempMemory( sizeof( png_bytep ) * h ); // set a new exception handler if ( setjmp( png_jmpbuf( png ) ) ) { ri.Printf( PRINT_WARNING, "LoadPNG: second exception handler called for (%s)\n", name ); ri.Hunk_FreeTempMemory( row_pointers ); ri.FS_FreeFile( data ); png_destroy_read_struct( &png, ( png_infopp ) & info, ( png_infopp ) nullptr ); return; } for ( row = 0; row < h; row++ ) { row_pointers[ row ] = ( png_bytep )( out + ( row * 4 * w ) ); } // read image data png_read_image( png, row_pointers ); // read rest of file, and get additional chunks in info png_read_end( png, info ); // clean up after the read, and free any memory allocated png_destroy_read_struct( &png, &info, ( png_infopp ) nullptr ); ri.Hunk_FreeTempMemory( row_pointers ); ri.FS_FreeFile( data ); }
void png_reader::read(unsigned x0, unsigned y0,image_data_32& image) { FILE *fp=fopen(fileName_.c_str(),"rb"); if (!fp) throw image_reader_exception("cannot open image file "+fileName_); png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,0,0,0); if (!png_ptr) { fclose(fp); throw image_reader_exception("failed to allocate png_ptr"); } // catch errors in a custom way to avoid the need for setjmp png_set_error_fn(png_ptr, png_get_error_ptr(png_ptr), user_error_fn, user_warning_fn); png_infop info_ptr; try { info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr,0,0); fclose(fp); throw image_reader_exception("failed to create info_ptr"); } } catch (std::exception const& ex) { png_destroy_read_struct(&png_ptr,0,0); fclose(fp); throw; } png_set_read_fn(png_ptr, (png_voidp)fp, png_read_data); png_read_info(png_ptr, info_ptr); if (color_type_ == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); if (color_type_ == PNG_COLOR_TYPE_GRAY && bit_depth_ < 8) png_set_expand(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(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); // quick hack -- only work in >=libpng 1.2.7 png_set_add_alpha(png_ptr,0xff,PNG_FILLER_AFTER); //rgba double gamma; if (png_get_gAMA(png_ptr, info_ptr, &gamma)) png_set_gamma(png_ptr, 2.2, gamma); if (x0 == 0 && y0 == 0 && image.width() >= width_ && image.height() >= height_) { if (png_get_interlace_type(png_ptr,info_ptr) == PNG_INTERLACE_ADAM7) { png_set_interlace_handling(png_ptr); // FIXME: libpng bug? // according to docs png_read_image // "..automatically handles interlacing, // so you don't need to call png_set_interlace_handling()" } png_read_update_info(png_ptr, info_ptr); // we can read whole image at once // alloc row pointers boost::scoped_array<png_byte*> rows(new png_bytep[height_]); for (unsigned i=0; i<height_; ++i) rows[i] = (png_bytep)image.getRow(i); png_read_image(png_ptr, rows.get()); } else { png_read_update_info(png_ptr, info_ptr); unsigned w=std::min(unsigned(image.width()),width_); unsigned h=std::min(unsigned(image.height()),height_); unsigned rowbytes=png_get_rowbytes(png_ptr, info_ptr); boost::scoped_array<png_byte> row(new png_byte[rowbytes]); //START read image rows for (unsigned i=0;i<height_;++i) { png_read_row(png_ptr,row.get(),0); if (i>=y0 && i<h) { image.setRow(i-y0,reinterpret_cast<unsigned*>(&row[x0]),w); } } //END } png_read_end(png_ptr,0); png_destroy_read_struct(&png_ptr, &info_ptr,0); fclose(fp); }
void PNGAPI png_read_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver, png_size_t png_struct_size) { #ifdef PNG_SETJMP_SUPPORTED jmp_buf tmp_jmp; /* to save current jump buffer */ #endif int i = 0; png_structp png_ptr=*ptr_ptr; if (png_ptr == NULL) return; do { if (user_png_ver[i] != png_libpng_ver[i]) { #ifdef PNG_LEGACY_SUPPORTED png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; #else png_ptr->warning_fn = NULL; png_warning(png_ptr, "Application uses deprecated png_read_init() and should be" " recompiled."); break; #endif } } while (png_libpng_ver[i++]); png_debug(1, "in png_read_init_3"); #ifdef PNG_SETJMP_SUPPORTED /* Save jump buffer and error functions */ png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf)); #endif if (png_sizeof(png_struct) > png_struct_size) { png_destroy_struct(png_ptr); *ptr_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); png_ptr = *ptr_ptr; } /* Reset all variables to 0 */ png_memset(png_ptr, 0, png_sizeof(png_struct)); #ifdef PNG_SETJMP_SUPPORTED /* Restore jump buffer */ png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf)); #endif /* Added at libpng-1.2.6 */ #ifdef PNG_SET_USER_LIMITS_SUPPORTED png_ptr->user_width_max = PNG_USER_WIDTH_MAX; png_ptr->user_height_max = PNG_USER_HEIGHT_MAX; #endif /* Initialize zbuf - compression buffer */ png_ptr->zbuf_size = PNG_ZBUF_SIZE; png_ptr->zstream.zalloc = png_zalloc; png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, (png_uint_32)png_ptr->zbuf_size); png_ptr->zstream.zalloc = png_zalloc; png_ptr->zstream.zfree = png_zfree; png_ptr->zstream.opaque = (voidpf)png_ptr; switch (inflateInit(&png_ptr->zstream)) { case Z_OK: /* Do nothing */ break; case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory error"); break; case Z_VERSION_ERROR: png_error(png_ptr, "zlib version error"); break; default: png_error(png_ptr, "Unknown zlib error"); } png_ptr->zstream.next_out = png_ptr->zbuf; png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; png_set_read_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL); }
ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE]) { struct ImBuf *ibuf = NULL; png_structp png_ptr; png_infop info_ptr; unsigned char *pixels = NULL; unsigned short *pixels16 = NULL; png_bytepp row_pointers = NULL; png_uint_32 width, height; int bit_depth, color_type; PNGReadStruct ps; unsigned char *from, *to; unsigned short *from16; float *to_float; int i, bytesperpixel; if (imb_is_a_png(mem) == 0) return(NULL); /* both 8 and 16 bit PNGs are default to standard byte colorspace */ colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { printf("Cannot png_create_read_struct\n"); return NULL; } png_set_error_fn(png_ptr, NULL, imb_png_error, imb_png_warning); info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); printf("Cannot png_create_info_struct\n"); return NULL; } ps.size = size; /* XXX, 4gig limit! */ ps.data = mem; ps.seek = 0; png_set_read_fn(png_ptr, (void *) &ps, ReadData); if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); if (pixels) MEM_freeN(pixels); if (pixels16) MEM_freeN(pixels16); if (row_pointers) MEM_freeN(row_pointers); if (ibuf) IMB_freeImBuf(ibuf); return NULL; } // png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); bytesperpixel = png_get_channels(png_ptr, info_ptr); switch (color_type) { case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: break; case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { bytesperpixel = 4; } else { bytesperpixel = 3; } break; case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_GRAY_ALPHA: if (bit_depth < 8) { png_set_expand(png_ptr); bit_depth = 8; } break; default: printf("PNG format not supported\n"); longjmp(png_jmpbuf(png_ptr), 1); break; } ibuf = IMB_allocImBuf(width, height, 8 * bytesperpixel, 0); if (ibuf) { ibuf->ftype = PNG; if (bit_depth == 16) ibuf->ftype |= PNG_16BIT; if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) { int unit_type; png_uint_32 xres, yres; if (png_get_pHYs(png_ptr, info_ptr, &xres, &yres, &unit_type)) if (unit_type == PNG_RESOLUTION_METER) { ibuf->ppm[0] = xres; ibuf->ppm[1] = yres; } } } else { printf("Couldn't allocate memory for PNG image\n"); } if (ibuf && ((flags & IB_test) == 0)) { if (bit_depth == 16) { imb_addrectfloatImBuf(ibuf); png_set_swap(png_ptr); pixels16 = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(png_uint_16), "pixels"); if (pixels16 == NULL) { printf("Cannot allocate pixels array\n"); longjmp(png_jmpbuf(png_ptr), 1); } /* allocate memory for an array of row-pointers */ row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_uint_16p), "row_pointers"); if (row_pointers == NULL) { printf("Cannot allocate row-pointers array\n"); longjmp(png_jmpbuf(png_ptr), 1); } /* set the individual row-pointers to point at the correct offsets */ for (i = 0; i < ibuf->y; i++) { row_pointers[ibuf->y - 1 - i] = (png_bytep) ((png_uint_16 *)pixels16 + (i * ibuf->x) * bytesperpixel); } png_read_image(png_ptr, row_pointers); /* copy image data */ to_float = ibuf->rect_float; from16 = pixels16; switch (bytesperpixel) { case 4: for (i = ibuf->x * ibuf->y; i > 0; i--) { to_float[0] = from16[0] / 65535.0; to_float[1] = from16[1] / 65535.0; to_float[2] = from16[2] / 65535.0; to_float[3] = from16[3] / 65535.0; to_float += 4; from16 += 4; } break; case 3: for (i = ibuf->x * ibuf->y; i > 0; i--) { to_float[0] = from16[0] / 65535.0; to_float[1] = from16[1] / 65535.0; to_float[2] = from16[2] / 65535.0; to_float[3] = 1.0; to_float += 4; from16 += 3; } break; case 2: for (i = ibuf->x * ibuf->y; i > 0; i--) { to_float[0] = to_float[1] = to_float[2] = from16[0] / 65535.0; to_float[3] = from16[1] / 65535.0; to_float += 4; from16 += 2; } break; case 1: for (i = ibuf->x * ibuf->y; i > 0; i--) { to_float[0] = to_float[1] = to_float[2] = from16[0] / 65535.0; to_float[3] = 1.0; to_float += 4; from16++; } break; } } else { imb_addrectImBuf(ibuf); pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels"); if (pixels == NULL) { printf("Cannot allocate pixels array\n"); longjmp(png_jmpbuf(png_ptr), 1); } /* allocate memory for an array of row-pointers */ row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers"); if (row_pointers == NULL) { printf("Cannot allocate row-pointers array\n"); longjmp(png_jmpbuf(png_ptr), 1); } /* set the individual row-pointers to point at the correct offsets */ for (i = 0; i < ibuf->y; i++) { row_pointers[ibuf->y - 1 - i] = (png_bytep) ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char)); } png_read_image(png_ptr, row_pointers); /* copy image data */ to = (unsigned char *) ibuf->rect; from = pixels; switch (bytesperpixel) { case 4: for (i = ibuf->x * ibuf->y; i > 0; i--) { to[0] = from[0]; to[1] = from[1]; to[2] = from[2]; to[3] = from[3]; to += 4; from += 4; } break; case 3: for (i = ibuf->x * ibuf->y; i > 0; i--) { to[0] = from[0]; to[1] = from[1]; to[2] = from[2]; to[3] = 0xff; to += 4; from += 3; } break; case 2: for (i = ibuf->x * ibuf->y; i > 0; i--) { to[0] = to[1] = to[2] = from[0]; to[3] = from[1]; to += 4; from += 2; } break; case 1: for (i = ibuf->x * ibuf->y; i > 0; i--) { to[0] = to[1] = to[2] = from[0]; to[3] = 0xff; to += 4; from++; } break; } } if (flags & IB_metadata) { png_text *text_chunks; int count = png_get_text(png_ptr, info_ptr, &text_chunks, NULL); for (i = 0; i < count; i++) { IMB_metadata_add_field(ibuf, text_chunks[i].key, text_chunks[i].text); ibuf->flags |= IB_metadata; } } png_read_end(png_ptr, info_ptr); } /* clean up */ if (pixels) MEM_freeN(pixels); if (pixels16) MEM_freeN(pixels16); if (row_pointers) MEM_freeN(row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return(ibuf); }
static void gst_pngdec_task (GstPad * pad) { GstPngDec *pngdec; GstBuffer *buffer = NULL; size_t buffer_size = 0; gint i = 0; png_bytep *rows, inp; png_uint_32 rowbytes; GstFlowReturn ret = GST_FLOW_OK; pngdec = GST_PNGDEC (GST_OBJECT_PARENT (pad)); GST_LOG_OBJECT (pngdec, "read frame"); /* Let libpng come back here on error */ if (setjmp (png_jmpbuf (pngdec->png))) { ret = GST_FLOW_ERROR; goto pause; } /* Set reading callback */ png_set_read_fn (pngdec->png, pngdec, user_read_data); /* Read info */ png_read_info (pngdec->png, pngdec->info); /* Generate the caps and configure */ ret = gst_pngdec_caps_create_and_set (pngdec); if (ret != GST_FLOW_OK) { goto pause; } /* Allocate output buffer */ rowbytes = png_get_rowbytes (pngdec->png, pngdec->info); buffer_size = pngdec->height * GST_ROUND_UP_4 (rowbytes); ret = gst_pad_alloc_buffer_and_set_caps (pngdec->srcpad, GST_BUFFER_OFFSET_NONE, buffer_size, GST_PAD_CAPS (pngdec->srcpad), &buffer); if (ret != GST_FLOW_OK) { goto pause; } rows = (png_bytep *) g_malloc (sizeof (png_bytep) * pngdec->height); inp = GST_BUFFER_DATA (buffer); for (i = 0; i < pngdec->height; i++) { rows[i] = inp; inp += GST_ROUND_UP_4 (rowbytes); } /* Read the actual picture */ png_read_image (pngdec->png, rows); free (rows); /* Push the raw RGB frame */ ret = gst_pad_push (pngdec->srcpad, buffer); if (ret != GST_FLOW_OK) { goto pause; } /* And we are done */ gst_pad_pause_task (pngdec->sinkpad); gst_pad_push_event (pngdec->srcpad, gst_event_new_eos ()); return; pause: GST_INFO_OBJECT (pngdec, "pausing task, reason %s", gst_flow_get_name (ret)); gst_pad_pause_task (pngdec->sinkpad); if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) { GST_ELEMENT_ERROR (pngdec, STREAM, FAILED, (_("Internal data stream error.")), ("stream stopped, reason %s", gst_flow_get_name (ret))); gst_pad_push_event (pngdec->srcpad, gst_event_new_eos ()); } }