static void readpng2_info_callback(png_structp png_ptr, png_infop info_ptr) { mainprog_info *mainprog_ptr; int color_type, bit_depth; png_uint_32 width, height; #ifdef PNG_FLOATING_POINT_SUPPORTED double gamma; #else png_fixed_point gamma; #endif /* setjmp() doesn't make sense here, because we'd either have to exit(), * longjmp() ourselves, or return control to libpng, which doesn't want * to see us again. By not doing anything here, libpng will instead jump * to readpng2_decode_data(), which can return an error value to the main * program. */ /* retrieve the pointer to our special-purpose struct, using the png_ptr * that libpng passed back to us (i.e., not a global this time--there's * no real difference for a single image, but for a multithreaded browser * decoding several PNG images at the same time, one needs to avoid mixing * up different images' structs) */ mainprog_ptr = png_get_progressive_ptr(png_ptr); if (mainprog_ptr == NULL) { /* we be hosed */ fprintf(stderr, "readpng2 error: main struct not recoverable in info_callback.\n"); fflush(stderr); return; /* * Alternatively, we could call our error-handler just like libpng * does, which would effectively terminate the program. Since this * can only happen if png_ptr gets redirected somewhere odd or the * main PNG struct gets wiped, we're probably toast anyway. (If * png_ptr itself is NULL, we would not have been called.) */ } /* this is just like in the non-progressive case */ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); mainprog_ptr->width = (ulg) width; mainprog_ptr->height = (ulg) height; /* since we know we've read all of the PNG file's "header" (i.e., up * to IDAT), we can check for a background color here */ if (mainprog_ptr->need_bgcolor && png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) { png_color_16p pBackground; /* it is not obvious from the libpng documentation, but this function * takes a pointer to a pointer, and it always returns valid red, * green and blue values, regardless of color_type: */ png_get_bKGD(png_ptr, info_ptr, &pBackground); /* however, it always returns the raw bKGD data, regardless of any * bit-depth transformations, so check depth and adjust if necessary */ if (bit_depth == 16) { mainprog_ptr->bg_red = pBackground->red >> 8; mainprog_ptr->bg_green = pBackground->green >> 8; mainprog_ptr->bg_blue = pBackground->blue >> 8; } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
GLuint XL::Texture2D::loadPNG(const std::string& filePNG) { //std::string fileName; //just in case //fileName = filePNG; //FILE* file = fopen(fileName.c_str(), "rb"); //assert(file); file.open(filePNG, std::ios::binary); unsigned char header[8]; file.read((char*)header, PNG_SIG_SIZE); //fread(header, 1, PNG_SIG_SIZE, file); if (!file.good()) { std::cout << "FILE NOT GOOD!" << std::endl; } if(png_sig_cmp(header, 0, 8)) { std::cout << filePNG.c_str() << " is not a PNG file" << std::endl; } png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); assert(pngPtr); png_infop infoPtr = png_create_info_struct(pngPtr); assert(infoPtr); png_bytep* rowPtrs = NULL; char* data = NULL; if (setjmp(png_jmpbuf(pngPtr))) { //this block executes when a libPNG error has occured png_destroy_read_struct(&pngPtr, (png_infopp)0, (png_infopp)0); delete[] rowPtrs; delete[] data; std::cout << "An error occured reading the PNG file." << std::endl; return 0; } png_set_read_fn(pngPtr, &file, XL::readData); /*png_init_io(pngPtr, &file);*/ //read the PNG file png_set_sig_bytes(pngPtr, PNG_SIG_SIZE); png_read_info(pngPtr, infoPtr); width = png_get_image_width(pngPtr, infoPtr); height = png_get_image_height(pngPtr, infoPtr); //bit depth per channel 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) png_uint_32 colorType = png_get_color_type(pngPtr, infoPtr); switch (colorType) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(pngPtr); channels = 3; break; case PNG_COLOR_TYPE_GRAY: if (bitDepth < 8) { png_set_expand_gray_1_2_4_to_8(pngPtr); bitDepth = 8; } break; } if (png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(pngPtr); channels++; } //strip the bit depth down to 8 if it is 16 //WHY?! CHECK THIS! if (bitDepth == 16) { png_set_strip_16(pngPtr); } //create an array of row pointers, one for every row, on the heap rowPtrs = new png_bytep[height]; //allocate a buffer with enough space (in bytes) int dataSize = width * height * bitDepth * channels / 8; data = new char[dataSize]; int dataWidth = dataSize / height; //length of a row in the data array //length in bytes of one row //MIGHT BE CULPRIT OF NON-WORKING 32-BIT PNG LOADING const unsigned int stride = width * bitDepth * channels / 8; for (size_t i = 0; i < height; i++) { png_uint_32 q = (height - i - 1) * stride; rowPtrs[i] = (png_bytep)data + q; } png_read_image(pngPtr, rowPtrs); //application crashes here //fclose(file); //flip the image char* newData = new char[dataSize]; for (int i = dataSize - dataWidth; i + 1 > 0; i -= dataWidth) { for (int k = 0; k < dataWidth; k++) { newData[dataSize - i - dataWidth + k] = data[i + k]; } } //Load OpenGL textures //add support for GL_RGB? glGenTextures(1, &id); glBindTexture(GL_TEXTURE_2D, id); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)newData); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glBindTexture(GL_TEXTURE_2D, NULL); png_destroy_read_struct(&pngPtr, &infoPtr, (png_infopp)0); delete[] rowPtrs; delete[] data; delete[] newData; return id; }
bool wxPNGHandler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index)) { // VZ: as this function uses setjmp() the only fool proof error handling // method is to use goto (setjmp is not really C++ dtors friendly...) unsigned char **lines = NULL; png_infop info_ptr = (png_infop) NULL; wxPNGInfoStruct wxinfo; wxinfo.verbose = verbose; wxinfo.stream.in = &stream; image->Destroy(); png_structp png_ptr = png_create_read_struct ( PNG_LIBPNG_VER_STRING, (voidp) NULL, wx_png_error, wx_png_warning ); if (!png_ptr) goto error; // NB: please see the comment near wxPNGInfoStruct declaration for // explanation why this line is mandatory png_set_read_fn( png_ptr, &wxinfo, wx_PNG_stream_reader); info_ptr = png_create_info_struct( png_ptr ); if (!info_ptr) goto error; if (setjmp(wxinfo.jmpbuf)) goto error; png_uint_32 i, width, height; int bit_depth, color_type, interlace_type; png_read_info( png_ptr, info_ptr ); png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, (int*) NULL, (int*) NULL ); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand( png_ptr ); // Fix for Bug [ 439207 ] Monochrome PNG images come up black if (bit_depth < 8) png_set_expand( png_ptr ); png_set_strip_16( png_ptr ); png_set_packing( png_ptr ); if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand( png_ptr ); png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER ); image->Create((int)width, (int)height, (bool) false /* no need to init pixels */); if (!image->Ok()) goto error; lines = (unsigned char **)malloc( (size_t)(height * sizeof(unsigned char *)) ); if ( !lines ) goto error; for (i = 0; i < height; i++) { if ((lines[i] = (unsigned char *)malloc( (size_t)(width * (sizeof(unsigned char) * 4)))) == NULL) { for ( unsigned int n = 0; n < i; n++ ) free( lines[n] ); goto error; } } png_read_image( png_ptr, lines ); png_read_end( png_ptr, info_ptr ); png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL ); // loaded successfully, now init wxImage with this data CopyDataFromPNG(image, lines, width, height, color_type); for ( i = 0; i < height; i++ ) free( lines[i] ); free( lines ); return true; error: if (verbose) wxLogError(_("Couldn't load a PNG image - file is corrupted or not enough memory.")); if ( image->Ok() ) { image->Destroy(); } if ( lines ) { free( lines ); } if ( png_ptr ) { if ( info_ptr ) { png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL ); free(info_ptr); } else png_destroy_read_struct( &png_ptr, (png_infopp) NULL, (png_infopp) NULL ); } return false; }
BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file, volatile BOOL raw, BOOL alpha) { png_struct *png_ptr = NULL; png_info *info_ptr = NULL; png_byte buf[8]; png_byte *png_pixels = NULL; png_byte **row_pointers = NULL; png_byte *pix_ptr = NULL; png_uint_32 row_bytes; png_uint_32 width; png_uint_32 height; int bit_depth; int channels; int color_type; int alpha_present; int row, col; int ret; int i; long dep_16; /* read and check signature in PNG file */ ret = fread (buf, 1, 8, png_file); if (ret != 8) return FALSE; ret = png_sig_cmp (buf, 0, 8); if (ret) return FALSE; /* create png and info structures */ png_ptr = png_create_read_struct (png_get_libpng_ver(NULL), NULL, NULL, NULL); if (!png_ptr) return FALSE; /* out of memory */ info_ptr = png_create_info_struct (png_ptr); if (!info_ptr) { png_destroy_read_struct (&png_ptr, NULL, NULL); return FALSE; /* out of memory */ } if (setjmp (png_jmpbuf(png_ptr))) { png_destroy_read_struct (&png_ptr, &info_ptr, NULL); return FALSE; } /* set up the input control for C streams */ png_init_io (png_ptr, png_file); png_set_sig_bytes (png_ptr, 8); /* we already read the 8 signature bytes */ /* read the file information */ png_read_info (png_ptr, info_ptr); /* get size and bit-depth of the PNG-image */ png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); /* set-up the transformations */ /* transform paletted images into full-color rgb */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand (png_ptr); /* expand images to bit-depth 8 (only applicable for grayscale images) */ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand (png_ptr); /* transform transparency maps into full alpha-channel */ if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand (png_ptr); #ifdef NJET /* downgrade 16-bit images to 8-bit */ if (bit_depth == 16) png_set_strip_16 (png_ptr); /* transform grayscale images into full-color */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb (png_ptr); /* only if file has a file gamma, we do a correction */ if (png_get_gAMA (png_ptr, info_ptr, &file_gamma)) png_set_gamma (png_ptr, (double) 2.2, file_gamma); #endif /* 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); /* get the new color-type and bit-depth (after expansion/stripping) */ png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); /* check for 16-bit files */ if (bit_depth == 16) { raw = FALSE; #ifdef __TURBOC__ pnm_file->flags &= ~((unsigned) _F_BIN); #endif } /* calculate new number of channels and store alpha-presence */ if (color_type == PNG_COLOR_TYPE_GRAY) channels = 1; else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) channels = 2; else if (color_type == PNG_COLOR_TYPE_RGB) channels = 3; else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) channels = 4; else channels = 0; /* should never happen */ alpha_present = (channels - 1) % 2; /* check if alpha is expected to be present in file */ if (alpha && !alpha_present) { fprintf (stderr, "PNG2PNM\n"); fprintf (stderr, "Error: PNG-file doesn't contain alpha channel\n"); exit (1); } /* row_bytes is the width x number of channels x (bit-depth / 8) */ row_bytes = png_get_rowbytes (png_ptr, info_ptr); if ((png_pixels = (png_byte *) malloc (row_bytes * height * sizeof (png_byte))) == NULL) { png_destroy_read_struct (&png_ptr, &info_ptr, NULL); return FALSE; } if ((row_pointers = (png_byte **) malloc (height * sizeof (png_bytep))) == NULL) { png_destroy_read_struct (&png_ptr, &info_ptr, NULL); free (png_pixels); png_pixels = NULL; return FALSE; } /* set the individual row_pointers to point at the correct offsets */ for (i = 0; i < ((int) height); i++) row_pointers[i] = png_pixels + i * row_bytes; /* now we can go ahead and just read the whole image */ 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); /* clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp) NULL); /* write header of PNM file */ if ((color_type == PNG_COLOR_TYPE_GRAY) || (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) { fprintf (pnm_file, "%s\n", (raw) ? "P5" : "P2"); fprintf (pnm_file, "%d %d\n", (int) width, (int) height); fprintf (pnm_file, "%ld\n", ((1L << (int) bit_depth) - 1L)); } else if ((color_type == PNG_COLOR_TYPE_RGB) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA)) { fprintf (pnm_file, "%s\n", (raw) ? "P6" : "P3"); fprintf (pnm_file, "%d %d\n", (int) width, (int) height); fprintf (pnm_file, "%ld\n", ((1L << (int) bit_depth) - 1L)); } /* write header of PGM file with alpha channel */ if ((alpha) && ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA))) { fprintf (alpha_file, "%s\n", (raw) ? "P5" : "P2"); fprintf (alpha_file, "%d %d\n", (int) width, (int) height); fprintf (alpha_file, "%ld\n", ((1L << (int) bit_depth) - 1L)); } /* write data to PNM file */ pix_ptr = png_pixels; for (row = 0; row < (int) height; row++) { for (col = 0; col < (int) width; col++) { for (i = 0; i < (channels - alpha_present); i++) { if (raw) fputc ((int) *pix_ptr++ , pnm_file); else if (bit_depth == 16){ dep_16 = (long) *pix_ptr++; fprintf (pnm_file, "%ld ", (dep_16 << 8) + ((long) *pix_ptr++)); } else fprintf (pnm_file, "%ld ", (long) *pix_ptr++); } if (alpha_present) { if (!alpha) { pix_ptr++; /* alpha */ if (bit_depth == 16) pix_ptr++; } else /* output alpha-channel as pgm file */ { if (raw) fputc ((int) *pix_ptr++ , alpha_file); else if (bit_depth == 16){ dep_16 = (long) *pix_ptr++; fprintf (alpha_file, "%ld ", (dep_16 << 8) + (long) *pix_ptr++); } else fprintf (alpha_file, "%ld ", (long) *pix_ptr++); } } /* if alpha_present */ if (!raw) if (col % 4 == 3) fprintf (pnm_file, "\n"); } /* end for col */ if (!raw) if (col % 4 != 0) fprintf (pnm_file, "\n"); } /* end for row */ if (row_pointers != (unsigned char**) NULL) free (row_pointers); if (png_pixels != (unsigned char*) NULL) free (png_pixels); return TRUE; } /* end of source */
void PNGAPI png_read_png(png_structp png_ptr, png_infop info_ptr, int transforms, voidp params) { int row; #if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) /* invert the alpha channel from opacity to transparency */ if (transforms & PNG_TRANSFORM_INVERT_ALPHA) png_set_invert_alpha(png_ptr); #endif /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). */ png_read_info(png_ptr, info_ptr); /* -------------- image transformations start here ------------------- */ #if defined(PNG_READ_16_TO_8_SUPPORTED) /* tell libpng to strip 16 bit/color files down to 8 bits/color */ if (transforms & PNG_TRANSFORM_STRIP_16) png_set_strip_16(png_ptr); #endif #if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) /* Strip alpha bytes from the input data without combining with the * background (not recommended). */ if (transforms & PNG_TRANSFORM_STRIP_ALPHA) png_set_strip_alpha(png_ptr); #endif #if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED) /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ if (transforms & PNG_TRANSFORM_PACKING) png_set_packing(png_ptr); #endif #if defined(PNG_READ_PACKSWAP_SUPPORTED) /* Change the order of packed pixels to least significant bit first * (not useful if you are using png_set_packing). */ if (transforms & PNG_TRANSFORM_PACKSWAP) png_set_packswap(png_ptr); #endif #if defined(PNG_READ_EXPAND_SUPPORTED) /* Expand paletted colors into true RGB triplets * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel * Expand paletted or RGB images with transparency to full alpha * channels so the data will be available as RGBA quartets. */ if (transforms & PNG_TRANSFORM_EXPAND) if ((png_ptr->bit_depth < 8) || (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) || (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))) png_set_expand(png_ptr); #endif /* We don't handle background color or gamma transformation or dithering. */ #if defined(PNG_READ_INVERT_SUPPORTED) /* invert monochrome files to have 0 as white and 1 as black */ if (transforms & PNG_TRANSFORM_INVERT_MONO) png_set_invert_mono(png_ptr); #endif #if defined(PNG_READ_SHIFT_SUPPORTED) /* If you want to shift the pixel values from the range [0,255] or * [0,65535] to the original [0,7] or [0,31], or whatever range the * colors were originally in: */ if ((transforms & PNG_TRANSFORM_SHIFT) && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) { png_color_8p sig_bit; png_get_sBIT(png_ptr, info_ptr, &sig_bit); png_set_shift(png_ptr, sig_bit); } #endif #if defined(PNG_READ_BGR_SUPPORTED) /* flip the RGB pixels to BGR (or RGBA to BGRA) */ if (transforms & PNG_TRANSFORM_BGR) png_set_bgr(png_ptr); #endif #if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ if (transforms & PNG_TRANSFORM_SWAP_ALPHA) png_set_swap_alpha(png_ptr); #endif #if defined(PNG_READ_SWAP_SUPPORTED) /* swap bytes of 16 bit files to least significant byte first */ if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) png_set_swap(png_ptr); #endif /* We don't handle adding filler bytes */ /* Optional call to gamma correct and add the background to the palette * and update info structure. REQUIRED if you are expecting libpng to * update the palette for you (i.e., you selected such a transform above). */ png_read_update_info(png_ptr, info_ptr); /* -------------- image transformations end here ------------------- */ #ifdef PNG_FREE_ME_SUPPORTED png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); #endif if(info_ptr->row_pointers == NULL) { info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr, info_ptr->height * sizeof(png_bytep)); #ifdef PNG_FREE_ME_SUPPORTED info_ptr->free_me |= PNG_FREE_ROWS; #endif for (row = 0; row < (int)info_ptr->height; row++) { info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); } } png_read_image(png_ptr, info_ptr->row_pointers); info_ptr->valid |= PNG_INFO_IDAT; /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); if(transforms == 0 || params == NULL) /* quiet compiler warnings */ return; }
int readpng_get_image(png_containerp ctx, uint32_t *pChannels, uint32_t *pRowBytes) { double display_exponent = 2.2; // sane default double gamma; png_uint_32 i, rowbytes; png_bytepp row_pointers = NULL; /* setjmp() must be called in every function that calls a PNG-reading * libpng function */ if (setjmp(png_jmpbuf(ctx->png))) { png_destroy_read_struct(&ctx->png, &ctx->info, NULL); return -1; } /* 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] */ if (ctx->color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(ctx->png); if (ctx->color_type == PNG_COLOR_TYPE_GRAY && ctx->bit_depth < 8) png_set_expand(ctx->png); if (png_get_valid(ctx->png, ctx->info, PNG_INFO_tRNS)) png_set_expand(ctx->png); if (ctx->bit_depth == 16) png_set_strip_16(ctx->png); if (ctx->color_type == PNG_COLOR_TYPE_GRAY || ctx->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(ctx->png); /* unlike the example in the libpng documentation, we have *no* idea where * this file may have come from--so if it doesn't have a file gamma, don't * do any correction ("do no harm") */ if (png_get_gAMA(ctx->png, ctx->info, &gamma)) png_set_gamma(ctx->png, display_exponent, gamma); /* all transformations have been registered; now update ctx->info data, * get rowbytes and channels, and allocate image memory */ png_read_update_info(ctx->png, ctx->info); *pRowBytes = rowbytes = png_get_rowbytes(ctx->png, ctx->info); *pChannels = png_get_channels(ctx->png, ctx->info); if ((ctx->bytes = (uint8_t*) malloc(rowbytes*ctx->height)) == NULL) { png_destroy_read_struct(&ctx->png, &ctx->info, NULL); return -1; } if ((row_pointers = (png_bytepp)malloc(ctx->height*sizeof(png_bytep))) == NULL) { png_destroy_read_struct(&ctx->png, &ctx->info, NULL); free(ctx->bytes); ctx->bytes = NULL; return -1; } /* set the individual row_pointers to point at the correct offsets */ for (i = 0; i < ctx->height; ++i) row_pointers[i] = ctx->bytes + i*rowbytes; /* now we can go ahead and just read the whole image */ png_read_image(ctx->png, row_pointers); /* and we're done! (png_read_end() can be omitted if no processing of * post-IDAT text/time/etc. is desired) */ free(row_pointers); row_pointers = NULL; png_read_end(ctx->png, NULL); return 0; }
int DisplayMakePNG(uint8_t *pu8Data, uint32_t cx, uint32_t cy, uint8_t **ppu8PNG, uint32_t *pcbPNG, uint32_t *pcxPNG, uint32_t *pcyPNG, uint8_t fLimitSize) { int rc = VINF_SUCCESS; uint8_t * volatile pu8Bitmap = NULL; /* gcc setjmp warning */ uint32_t volatile cbBitmap = 0; /* gcc setjmp warning */ uint32_t volatile cxBitmap = 0; /* gcc setjmp warning */ uint32_t volatile cyBitmap = 0; /* gcc setjmp warning */ if (!fLimitSize || (cx < kMaxSizePNG && cy < kMaxSizePNG)) { /* Save unscaled screenshot. */ pu8Bitmap = pu8Data; cbBitmap = cx * 4 * cy; cxBitmap = cx; cyBitmap = cy; } else { /* Large screenshot, scale. */ if (cx > cy) { cxBitmap = kMaxSizePNG; cyBitmap = (kMaxSizePNG * cy) / cx; } else { cyBitmap = kMaxSizePNG; cxBitmap = (kMaxSizePNG * cx) / cy; } cbBitmap = cxBitmap * 4 * cyBitmap; pu8Bitmap = (uint8_t *)RTMemAlloc(cbBitmap); if (pu8Bitmap) { uint8_t *dst = pu8Bitmap; uint8_t *src = pu8Data; int dstW = cxBitmap; int dstH = cyBitmap; int srcW = cx; int srcH = cy; int iDeltaLine = cx * 4; BitmapScale32 (dst, dstW, dstH, src, iDeltaLine, srcW, srcH); } else { rc = VERR_NO_MEMORY; } } LogFlowFunc(("%dx%d -> %dx%d\n", cx, cy, cxBitmap, cyBitmap)); if (RT_SUCCESS(rc)) { png_bytep *row_pointers = (png_bytep *)RTMemAlloc(cyBitmap * sizeof(png_bytep)); if (row_pointers) { png_infop info_ptr = NULL; png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, /* error/warning context pointer */ (png_error_ptr)NULL, /* error function */ (png_error_ptr)NULL /* warning function */); if (png_ptr) { info_ptr = png_create_info_struct(png_ptr); if (info_ptr) { if (!setjmp(png_jmpbuf(png_ptr))) { PNGWriteCtx ctx; ctx.pu8PNG = NULL; ctx.cbPNG = 0; ctx.cbAllocated = 0; ctx.rc = VINF_SUCCESS; png_set_write_fn(png_ptr, (png_voidp)&ctx, png_write_data_fn, png_output_flush_fn); png_set_IHDR(png_ptr, info_ptr, cxBitmap, cyBitmap, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_bytep row_pointer = (png_bytep)pu8Bitmap; unsigned i = 0; for (; i < cyBitmap; i++, row_pointer += cxBitmap * 4) { row_pointers[i] = row_pointer; } png_set_rows(png_ptr, info_ptr, &row_pointers[0]); png_write_info(png_ptr, info_ptr); png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); png_set_bgr(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_IDAT)) png_write_image(png_ptr, png_get_rows(png_ptr, info_ptr)); png_write_end(png_ptr, info_ptr); rc = ctx.rc; if (RT_SUCCESS(rc)) { *ppu8PNG = ctx.pu8PNG; *pcbPNG = ctx.cbPNG; *pcxPNG = cxBitmap; *pcyPNG = cyBitmap; LogFlowFunc(("PNG %d bytes, bitmap %d bytes\n", ctx.cbPNG, cbBitmap)); } } else { rc = VERR_GENERAL_FAILURE; /* Something within libpng. */ } } else { rc = VERR_NO_MEMORY; } png_destroy_write_struct(&png_ptr, info_ptr ? &info_ptr : (png_infopp)NULL); } else { rc = VERR_NO_MEMORY; } RTMemFree(row_pointers); } else { rc = VERR_NO_MEMORY; } } if (pu8Bitmap && pu8Bitmap != pu8Data) { RTMemFree(pu8Bitmap); } return rc; }
unsigned char * readpng_get_image(unsigned char *png_data, unsigned int png_size, png_uint_32 *width, png_uint_32 *height) { unsigned char *rgba = NULL; png_structp png_ptr; png_infop info_ptr; int bit_depth; int colour_type; png_uint_32 i, rowbytes; png_bytepp row_pointers = NULL; /* check the signature */ if(!png_check_sig(png_data, 8)) return NULL; /* init libpng data structures */ if((png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) == NULL) return NULL; if((info_ptr = png_create_info_struct(png_ptr)) == NULL) { png_destroy_read_struct(&png_ptr, NULL, NULL); return NULL; } /* setjmp() must be called in every function that calls a PNG-reading libpng function */ if(setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); if(row_pointers != NULL) free(row_pointers); if(rgba != NULL) free(rgba); return NULL; } /* read from memory rather than a file */ read_mem_state.data = png_data; read_mem_state.size = png_size; /* unlike file IO we don't need to seek passed the signature */ read_mem_state.used = 0; png_set_read_fn(png_ptr, &read_mem_state, read_mem); /* read all PNG info up to image data */ png_read_info(png_ptr, info_ptr); /* don't care about compression_type and filter_type => NULL */ png_get_IHDR(png_ptr, info_ptr, width, height, &bit_depth, &colour_type, NULL, NULL, NULL); /* expand palette images to RGB */ if((colour_type & PNG_COLOR_MASK_PALETTE) != 0) png_set_expand(png_ptr); /* expand low-bit-depth images to 8 bits */ if(bit_depth < 8) png_set_expand(png_ptr); /* expand transparency chunks to full alpha channel */ if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); /* strip 16-bit-per-sample images to 8-bits-per-sample */ if(bit_depth == 16) png_set_strip_16(png_ptr); /* convert grayscale to RGB */ if((colour_type & PNG_COLOR_MASK_COLOR) == 0) png_set_gray_to_rgb(png_ptr); /* add an opaque alpha channel if none exists in the PNG file */ if((colour_type & PNG_COLOR_MASK_ALPHA) == 0) png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER); /* recalc rowbytes etc */ png_read_update_info(png_ptr, info_ptr); /* assert */ if(png_get_channels(png_ptr, info_ptr) != 4) fatal("readpng: didn't get 4 channels"); /* alloc our RGBA array */ rowbytes = png_get_rowbytes(png_ptr, info_ptr); if((rgba = (unsigned char *) malloc(rowbytes * (*height))) == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } if((row_pointers = (png_bytepp) malloc((*height) * sizeof(png_bytep))) == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); free(rgba); return NULL; } /* set the individual row_pointers to point at the correct offsets */ for(i=0; i<(*height); i++) row_pointers[i] = rgba + (i * rowbytes); /* now we can go ahead and just read the whole image */ png_read_image(png_ptr, row_pointers); /* clean up */ free(row_pointers); row_pointers = NULL; png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return rgba; }
static uint8_t png_read( png_structp readPtr, png_image * image, uint32_t flags ) { // png_set_error_fn( readPtr, NULL, png_user_error, NULL ); png_infop infoPtr = png_create_info_struct( readPtr ); if (!infoPtr) { pngio_error( "Couldn't initialize PNG info struct." ); png_destroy_read_struct( & readPtr, NULL, NULL ); return 0; } if (setjmp( png_jmpbuf( readPtr ) )) { pngio_error( "An error occured while reading the PNG file." ); png_destroy_read_struct( & readPtr, & infoPtr, NULL ); png_image_free( image ); return 0; } png_set_sig_bytes( readPtr, 8 ); #ifdef PNG_APPLE_MODE_SUPPORTED if (png_get_apple_mode()) { png_set_keep_unknown_chunks( readPtr, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0 ); png_set_read_user_chunk_fn( readPtr, NULL, png_read_user_chunk ); } #endif png_read_info( readPtr, infoPtr ); png_uint_32 w = png_get_image_width( readPtr, infoPtr ); png_uint_32 h = png_get_image_height( readPtr, infoPtr ); png_uint_32 bitDepth = png_get_bit_depth( readPtr, infoPtr ); png_uint_32 channels = png_get_channels( readPtr, infoPtr ); png_uint_32 interlaceType = png_get_interlace_type( readPtr, infoPtr ); png_uint_32 colorType = png_get_color_type( readPtr, infoPtr ); switch (colorType) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb( readPtr ); channels = 3; break; case PNG_COLOR_TYPE_GRAY: if (bitDepth < 8) { png_set_expand_gray_1_2_4_to_8( readPtr ); bitDepth = 8; } png_set_gray_to_rgb( readPtr ); break; } if (png_get_valid( readPtr, infoPtr, PNG_INFO_tRNS )) { png_set_tRNS_to_alpha( readPtr ); channels += 1; } else if (!(colorType & PNG_COLOR_MASK_ALPHA)) { png_set_add_alpha( readPtr, 0xff, PNG_FILLER_AFTER ); } if (bitDepth == 16) { png_set_strip_16( readPtr ); } #ifdef PNG_APPLE_MODE_SUPPORTED if (png_get_apple_mode()) { if (flags & PNG_IMAGE_PREMULTIPLY_ALPHA) { png_set_read_user_transform_fn( readPtr, png_read_swap_transform ); } else { png_set_read_user_transform_fn( readPtr, png_read_swap_and_unpremultiply_transform ); } png_set_user_transform_info( readPtr, NULL, bitDepth, channels ); png_read_update_info( readPtr, infoPtr ); } else #endif { if (flags & PNG_IMAGE_PREMULTIPLY_ALPHA) { png_set_read_user_transform_fn( readPtr, png_read_premultiply_transform ); } } png_image_alloc( image, w, h ); png_bytep p = image->data; const size_t passCount = interlaceType == PNG_INTERLACE_NONE ? 1 : png_set_interlace_handling( readPtr ); const size_t bytesPerRow = w * 4; if (flags & PNG_IMAGE_FLIP_VERTICAL) { for (size_t pass = 0; pass < passCount; pass++) { for (size_t i = 0; i < h; i++) { png_read_row( readPtr, p + (bytesPerRow * (h - i - 1)), NULL ); } } } else { // png_bytep rp[h]; // for (size_t i = 0; i < h; i++) // { // rp[i] = p + (bytesPerRow * i); // } // png_read_image( readPtr, rp ); for (size_t pass = 0; pass < passCount; pass++) { for (size_t i = 0; i < h; i++) { png_read_row( readPtr, p + (bytesPerRow * i), NULL ); } } } png_destroy_read_struct( & readPtr, & infoPtr, NULL ); return 1; }
void ReadFilePNG(CByteImage& img, const char* filename) { // open the PNG input file FILE *stream = fopen(filename, "rb"); if (stream == 0) throw CError("ReadFilePNG: could not open %s", filename); // first check the eight byte PNG signature png_byte pbSig[8]; fread(pbSig, 1, 8, stream); if (!png_check_sig(pbSig, 8)) { fclose(stream); throw CError("ReadFilePNG: invalid PNG signature"); } // create the two png(-info) structures png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, (png_error_ptr)pngfile_error, (png_error_ptr)NULL); if (!png_ptr) { fclose(stream); throw CError("ReadFilePNG: error creating png structure"); } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); fclose(stream); throw CError("ReadFilePNG: error creating png structure"); } png_init_io(png_ptr, stream); png_set_sig_bytes(png_ptr, 8); // read all PNG info up to image data png_read_info(png_ptr, info_ptr); // get width, height, bit-depth and color-type int width, height, bits, colorType, nBands; png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *)&width, (png_uint_32 *)&height, &bits, &colorType, NULL, NULL, NULL); nBands = (int)png_get_channels(png_ptr, info_ptr); if (DEBUG_ImageIOpng) fprintf(stderr, " w=%d, h=%d, %2d bits, %s, nB=%d", width, height, bits, colorType == PNG_COLOR_TYPE_GRAY ? "gray" : colorType == PNG_COLOR_TYPE_PALETTE ? "plt " : colorType == PNG_COLOR_TYPE_RGB ? "rgb " : colorType == PNG_COLOR_TYPE_RGB_ALPHA ? "rgba" : colorType == PNG_COLOR_TYPE_GRAY_ALPHA ? "gr-a" : "??? ", nBands); // get rid of lower-order byte in 16-bit images // TODO: could allow this and read in IntImage in this case... if (bits == 16) png_set_strip_16(png_ptr); // change palette color into RGB if (colorType == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); // want at least 8 bits if (bits < 8) png_set_expand(png_ptr); // if there is a transparent palette entry, create alpha channel if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); // make gray images with alpha channel into RGBA -- TODO: or just ignore alpha? if (colorType == PNG_COLOR_TYPE_GRAY_ALPHA) // colorType == PNG_COLOR_TYPE_GRAY // but leave gray images alone png_set_gray_to_rgb(png_ptr); // set the background color to draw transparent and alpha images over. // only needed for gray images with alpha if (colorType == PNG_COLOR_TYPE_GRAY_ALPHA || colorType == PNG_COLOR_TYPE_GRAY) { png_color_16 *pBackground; if (png_get_bKGD(png_ptr, info_ptr, &pBackground)) png_set_background(png_ptr, pBackground, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); } // if required set gamma conversion // this seems to cause problems, so let's just leave gamma alone. //double gamma; //if (png_get_gAMA(png_ptr, info_ptr, &gamma)) { // //fprintf(stderr, "\n reading gamma %lf\n", gamma); //png_set_gamma(png_ptr, 1.0, gamma); //} // we need colors in BGR order, not RGB png_set_bgr(png_ptr); // always convert 3-band to 4-band images (add alpha): if (colorType == PNG_COLOR_TYPE_RGB) png_set_add_alpha(png_ptr, 255, PNG_FILLER_AFTER); // after the transformations have been registered update info_ptr data png_read_update_info(png_ptr, info_ptr); // get again width, height and the new bit-depth and color-type png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *)&width, (png_uint_32 *)&height, &bits, &colorType, NULL, NULL, NULL); nBands = (int)png_get_channels(png_ptr, info_ptr); if (DEBUG_ImageIOpng) fprintf(stderr, " -> w=%d, h=%d, %2d bits, %s, nB=%d\n", width, height, bits, colorType == PNG_COLOR_TYPE_GRAY ? "gray" : colorType == PNG_COLOR_TYPE_PALETTE ? "plt " : colorType == PNG_COLOR_TYPE_RGB ? "rgb " : colorType == PNG_COLOR_TYPE_RGB_ALPHA ? "rgba" : colorType == PNG_COLOR_TYPE_GRAY_ALPHA ? "gr-a" : "??? ", nBands); if (! (nBands==1 || nBands==3 || nBands==4)) { fclose(stream); throw CError("ReadFilePNG: Can't handle nBands=%d", nBands); } // Set the image shape CShape sh(width, height, nBands); // Allocate the image if necessary img.ReAllocate(sh); // allocate a vector of row pointers std::vector<uchar *> rowPtrs; rowPtrs.resize(height); for (int y = 0; y<height; y++) rowPtrs[y] = &img.Pixel(0, y, 0); // read the whole image png_read_image(png_ptr, &rowPtrs[0]); // read the additional chunks in the PNG file (not really needed) png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(stream); }
void ZLEwlImageManager::convertImageDirectPng(const std::string &stringData, ZLImageData &data) const { struct s_my_png my_png; my_png.p = (char*)stringData.data(); my_png.size = stringData.length(); png_structp png_ptr = NULL; png_infop info_ptr = NULL; unsigned int *row = NULL; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)&my_png, mypng_error_func, mypng_warning_func); if ( !png_ptr ) return; if (setjmp( png_ptr->jmpbuf )) { data.init(0, 0); if (png_ptr) { png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); } if ( row ) delete row; return; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) mypng_error_func(png_ptr, "cannot create png info struct"); png_set_read_fn(png_ptr, (voidp)&my_png, mypng_read_func); png_read_info( png_ptr, info_ptr ); png_uint_32 width, height; int bit_depth, color_type, interlace_type; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); data.init(width, height); row = new unsigned int[ width ]; // SET TRANSFORMS if (color_type & PNG_COLOR_MASK_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 (bit_depth == 16) png_set_strip_16(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_invert_alpha(png_ptr); } else { png_color_16 bg = {0, 0xffff, 0xffff, 0xffff, 0xffff}; png_set_background(png_ptr, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 0.0); png_set_strip_alpha(png_ptr); } if (bit_depth < 8) png_set_packing(png_ptr); //if (color_type == PNG_COLOR_TYPE_RGB) //png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); //if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) // png_set_swap_alpha(png_ptr); if (! (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) png_set_rgb_to_gray(png_ptr, 1, -1, -1); int number_passes = png_set_interlace_handling(png_ptr); //if (color_type == PNG_COLOR_TYPE_RGB_ALPHA || // color_type == PNG_COLOR_TYPE_GRAY_ALPHA) //if (color_type == PNG_COLOR_TYPE_RGB || // color_type == PNG_COLOR_TYPE_RGB_ALPHA) png_set_bgr(png_ptr); ZLIntegerOption myDitherAlgo(ZLCategoryKey::LOOK_AND_FEEL, "Options", "DitherAlgo", 0); register int dalgo = myDitherAlgo.value(); char *c; for(int pass = 0; pass < number_passes; pass++) { for(unsigned int y = 0; y < height; y++) { png_read_rows(png_ptr, (unsigned char **)&row, png_bytepp_NULL, 1); c = ((ZLEwlImageData&)data).getImageData() + width * y; if ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) { unsigned char *s = (unsigned char*)row; if(dalgo == 1) for(unsigned int i = 0; i < width; i++) *c++ = Dither2BitColor(*(++s)++, i, y); else for(unsigned int i = 0; i < width; i++) *c++ = *(++s)++; } else if(dalgo == 1) { unsigned char *s = (unsigned char*)row; for(unsigned int i = 0; i < width; i++) *c++ = Dither2BitColor(*s++, i, y); } else memcpy(c, (char*)row, width); } } png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); }
/*--------------------------------------------------------------------------- Loads a PNG file. Image : Image will be returned there. Path : Path to image file, relative to the current working directory. Gamma : Display gamma to apply on textures, 2.2 is typical. ---------------------------------------------------------------------------*/ void PNG::Load(Texture &Image, const std::string &Path, float Gamma) { Destroy(); //Important - set class to reading mode Mode = PNG::ModeRead; #if defined (WINDOWS) if (fopen_s(&File, Path.c_str(), "rb") != 0) {throw dexception("Failed to open file: %s.", Path.c_str());} #else File = fopen(Path.c_str(), "rb"); if (File == nullptr) {throw dexception("Failed to open file: %s.", Path.c_str());} #endif uint8 Header[PNG::HeaderSize]; if (fread((png_bytep)Header, 1, PNG::HeaderSize, File) == 0) {throw dexception("fread( ) failed.");} if (!png_check_sig(Header, PNG::HeaderSize)) {throw dexception("Not a valid PNG file.");} PngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (PngPtr == nullptr) {throw dexception("png_create_read_struct( ) failed.");} InfoPtr = png_create_info_struct(PngPtr); if (InfoPtr == nullptr) {throw dexception("png_create_info_struct( ) failed.");} if (setjmp(png_jmpbuf(PngPtr))) {throw dexception("setjmp( ) failed.");} //Read into structures png_init_io(PngPtr, File); png_set_sig_bytes(PngPtr, PNG::HeaderSize); png_read_info(PngPtr, InfoPtr); //Determine image attributes vector2<png_uint_32> Res; int BitDepth, ColourType; png_get_IHDR(PngPtr, InfoPtr, &Res.U, &Res.V, &BitDepth, &ColourType, nullptr, nullptr, nullptr); Texture::TexType Type = Texture::TypeRGB; switch (ColourType) { case PNG_COLOR_TYPE_GRAY : if (BitDepth < 8) { Type = Texture::TypeLum; png_set_expand_gray_1_2_4_to_8(PngPtr); } else if (BitDepth == 16) { Type = Texture::TypeDepth; } break; case PNG_COLOR_TYPE_GRAY_ALPHA : Type = Texture::TypeRGBA; png_set_gray_to_rgb(PngPtr); break; case PNG_COLOR_TYPE_PALETTE : Type = Texture::TypeRGB; png_set_palette_to_rgb(PngPtr); break; case PNG_COLOR_TYPE_RGB : Type = Texture::TypeRGB; png_set_strip_alpha(PngPtr); //If libpng reports RGB, make sure we completely strip alpha break; case PNG_COLOR_TYPE_RGB_ALPHA : Type = Texture::TypeRGBA; break; default : throw dexception("Unknown colour type."); } //Convert palette alpha into a separate alpha channel if (png_get_valid(PngPtr, InfoPtr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(PngPtr); if (ColourType == PNG_COLOR_TYPE_PALETTE) {Type = Texture::TypeRGBA;} } //Force 8 bit per channel if (BitDepth >= 16) { if (Type != Texture::TypeDepth) {png_set_strip_16(PngPtr);} } else if (BitDepth < 8) { png_set_packing(PngPtr); } //Specify display and file gamma (assume 0.45455 for missing file gamma) double FileGamma; if (!png_get_gAMA(PngPtr, InfoPtr, &FileGamma)) {FileGamma = 0.45455;} png_set_gamma(PngPtr, Gamma, FileGamma); //Swap byte order for int16 values on big endian machines if ((BitDepth >= 16) && !Math::MachineLittleEndian()) {png_set_swap(PngPtr);} //Apply the above transformation settings png_read_update_info(PngPtr, InfoPtr); //Allocate image Image.Create(cast_vector2(uint, Res), Type); if (Image.GetBytesPerLine() < (usize)png_get_rowbytes(PngPtr, InfoPtr)) {throw dexception("Incorrect scan line size for allocated image.");} //Populate row pointer array Rows.Create((usize)Res.V); for (uiter I = 0; I < (usize)Res.V; I++) { Rows[I] = Image.Address(0, I); } //Decode png_read_image(PngPtr, Rows.Pointer()); png_read_end(PngPtr, InfoPtr); //Clean up Destroy(); }
// TODO: clean up error handling, too much dupe code right now bool PNG::_read_file(string const & file_name) { // unfortunately, we need to break down to the C-code level here, since // libpng is written in C itself // we need to open the file in binary mode FILE * fp = fopen(file_name.c_str(), "rb"); if (!fp) { epng_err("Failed to open " + file_name); return false; } // read in the header (max size of 8), use it to validate this as a PNG file png_byte header[8]; fread(header, 1, 8, fp); if (png_sig_cmp(header, 0, 8)) { epng_err("File is not a valid PNG file"); fclose(fp); _init(); return false; } // set up libpng structs for reading info png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { epng_err("Failed to create read struct"); fclose(fp); _init(); return false; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { epng_err("Failed to create info struct"); png_destroy_read_struct(&png_ptr, NULL, NULL); fclose(fp); _init(); return false; } // set error handling to not abort the entire program if (setjmp(png_jmpbuf(png_ptr))) { epng_err("Error initializing libpng io"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); _init(); return false; } // initialize png reading png_init_io(png_ptr, fp); // let it know we've already read the first 8 bytes png_set_sig_bytes(png_ptr, 8); // read in the basic image info png_read_info(png_ptr, info_ptr); // convert to 8 bits png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); // verify this is in RGBA format, and if not, convert it to RGBA png_byte color_type = png_get_color_type(png_ptr, info_ptr); if (color_type != PNG_COLOR_TYPE_RGBA && color_type != PNG_COLOR_TYPE_RGB) { if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (bit_depth < 8) png_set_expand(png_ptr); png_set_gray_to_rgb(png_ptr); } if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); } // convert tRNS to alpha channel if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); _width = png_get_image_width(png_ptr, info_ptr); _height = png_get_image_height(png_ptr, info_ptr); png_read_update_info(png_ptr, info_ptr); // begin reading in the image if (setjmp(png_jmpbuf(png_ptr))) { epng_err("Error reading image with libpng"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); _init(); return false; } int bpr = png_get_rowbytes(png_ptr, info_ptr); // number of bytes in a row int numchannels = png_get_channels(png_ptr, info_ptr); // initialie our image storage _pixels = new RGBAPixel[_height * _width]; png_byte * row = new png_byte[bpr]; for (int y = 0; y < _height; y++) { png_read_row(png_ptr, row, NULL); png_byte * pix = row; for (int x = 0; x < _width; x++) { RGBAPixel & pixel = _pixel(x,y); if (numchannels == 1 || numchannels == 2) { // monochrome unsigned char color = (unsigned char) *pix++; pixel.red = color; pixel.green = color; pixel.blue = color; if (numchannels == 2) pixel.alpha = (unsigned char) *pix++; else pixel.alpha = 255; } else if (numchannels == 3 || numchannels == 4) { pixel.red = (unsigned char) *pix++; pixel.green = (unsigned char) *pix++; pixel.blue = (unsigned char) *pix++; if (numchannels == 4) pixel.alpha = (unsigned char) *pix++; else pixel.alpha = 255; } } } // cleanup delete [] row; png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return true; }
static DFBResult load_image (const char *filename, DFBSurfaceDescription *desc) { DFBSurfacePixelFormat dest_format; DFBSurfacePixelFormat src_format; FILE *fp; png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_uint_32 width, height; unsigned char *data = NULL; int type; char header[8]; int bytes, pitch; dest_format = (desc->flags & DSDESC_PIXELFORMAT) ? desc->pixelformat : DSPF_UNKNOWN; desc->flags = DSDESC_NONE; desc->preallocated[0].data = NULL; if (!(fp = fopen (filename, "rb"))) { fprintf (stderr, "Failed to open file '%s': %s.\n", filename, strerror (errno)); goto cleanup; } bytes = fread (header, 1, sizeof(header), fp); if (png_sig_cmp ((unsigned char*) header, 0, bytes)) { fprintf (stderr, "File '%s' doesn't seem to be a PNG image file.\n", filename); goto cleanup; } png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) goto cleanup; if (setjmp (png_jmpbuf(png_ptr))) { if (desc->preallocated[0].data) { free (desc->preallocated[0].data); desc->preallocated[0].data = NULL; } /* data might have been clobbered, set it to NULL and leak instead of crashing */ data = NULL; goto cleanup; } info_ptr = png_create_info_struct (png_ptr); if (!info_ptr) goto cleanup; png_init_io (png_ptr, fp); png_set_sig_bytes (png_ptr, bytes); png_read_info (png_ptr, info_ptr); png_get_IHDR (png_ptr, info_ptr, &width, &height, &bytes, &type, NULL, NULL, NULL); if (bytes == 16) png_set_strip_16 (png_ptr); #ifdef WORDS_BIGENDIAN png_set_swap_alpha (png_ptr); #else png_set_bgr (png_ptr); #endif src_format = (type & PNG_COLOR_MASK_ALPHA) ? DSPF_ARGB : DSPF_RGB32; switch (type) { case PNG_COLOR_TYPE_GRAY: if (dest_format == DSPF_A8) { src_format = DSPF_A8; break; } /* fallthru */ case PNG_COLOR_TYPE_GRAY_ALPHA: png_set_gray_to_rgb (png_ptr); // if (rgbformat) // dest_format = rgbformat; break; case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb (png_ptr); /* fallthru */ case PNG_COLOR_TYPE_RGB: // if (rgbformat) // dest_format = rgbformat; case PNG_COLOR_TYPE_RGB_ALPHA: if (dest_format == DSPF_RGB24) { png_set_strip_alpha (png_ptr); src_format = DSPF_RGB24; } break; } switch (src_format) { case DSPF_RGB32: png_set_filler (png_ptr, 0xFF, #ifdef WORDS_BIGENDIAN PNG_FILLER_BEFORE #else PNG_FILLER_AFTER #endif ); break; case DSPF_ARGB: case DSPF_A8: if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha (png_ptr); break; default: break; } pitch = (DFB_BYTES_PER_LINE( src_format, width ) + 7) & ~7; data = (unsigned char*) malloc (height * pitch); if (!data) { fprintf (stderr, "Failed to allocate %lu bytes.\n", (unsigned long)(height * pitch)); goto cleanup; } { unsigned int i; png_bytep bptrs[height]; for (i = 0; i < height; i++) bptrs[i] = data + i * pitch; png_read_image (png_ptr, bptrs); } if (!dest_format) dest_format = src_format; if (DFB_BYTES_PER_PIXEL(src_format) != DFB_BYTES_PER_PIXEL(dest_format)) { unsigned char *s, *d, *dest; int d_pitch, h; D_ASSERT( DFB_BYTES_PER_PIXEL(src_format) == 4 ); d_pitch = (DFB_BYTES_PER_LINE(dest_format, width) + 7) & ~7; dest = (unsigned char*) malloc (height * d_pitch); if (!dest) { fprintf (stderr, "Failed to allocate %lu bytes.\n", (unsigned long)(height * d_pitch)); goto cleanup; } h = height; switch (dest_format) { case DSPF_RGB16: for (s = data, d = dest; h; h--, s += pitch, d += d_pitch) dfb_argb_to_rgb16 ((u32 *) s, (u16 *) d, width); break; case DSPF_ARGB8565: for (s = data, d = dest; h; h--, s += pitch, d += d_pitch) dfb_argb_to_argb8565 ((u32 *) s, (u8 *) d, width); break; case DSPF_ARGB1555: for (s = data, d = dest; h; h--, s += pitch, d += d_pitch) dfb_argb_to_argb1555 ((u32 *) s, (u16 *) d, width); break; case DSPF_RGBA5551: for (s = data, d = dest; h; h--, s += pitch, d += d_pitch) dfb_argb_to_rgba5551 ((u32 *) s, (u16 *) d, width); break; case DSPF_ARGB2554: for (s = data, d = dest; h; h--, s += pitch, d += d_pitch) dfb_argb_to_argb2554 ((u32 *) s, (u16 *) d, width); break; case DSPF_ARGB4444: for (s = data, d = dest; h; h--, s += pitch, d += d_pitch) dfb_argb_to_argb4444 ((u32 *) s, (u16 *) d, width); break; case DSPF_RGB332: for (s = data, d = dest; h; h--, s += pitch, d += d_pitch) dfb_argb_to_rgb332 ((u32 *) s, (u8 *) d, width); break; case DSPF_A8: for (s = data, d = dest; h; h--, s += pitch, d += d_pitch) dfb_argb_to_a8 ((u32 *) s, (u8 *) d, width); break; default: fprintf (stderr, "Sorry, unsupported format conversion.\n"); goto cleanup; } free (data); data = dest; pitch = d_pitch; } desc->flags = (DFBSurfaceDescriptionFlags)(DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT | DSDESC_PREALLOCATED); desc->width = width; desc->height = height; desc->pixelformat = dest_format; desc->preallocated[0].pitch = pitch; desc->preallocated[0].data = data; data = NULL; cleanup: if (fp) fclose (fp); if (png_ptr) png_destroy_read_struct (&png_ptr, &info_ptr, NULL); if (data) free (data); return ((desc->flags) ? DFB_OK : DFB_FAILURE); }
static void LoadPNGBuffer( byte *buffer, int size, byte **pixels, int *width, int *height ){ png_struct *png; png_info *info, *end; pngBuffer_t pb; //pngBuffer_t *pb = (pngBuffer_t*) png_get_io_ptr( png ); int bitDepth, colorType; png_uint_32 w, h, i; byte **rowPointers; /* dummy check */ if ( buffer == NULL || size <= 0 || pixels == NULL || width == NULL || height == NULL ) { return; } /* null out */ *pixels = 0; *width = 0; *height = 0; /* determine if this is a png file */ if ( png_sig_cmp( buffer, 0, 8 ) != 0 ) { Sys_Printf( "WARNING: Invalid PNG file\n" ); return; } /* create png structs */ png = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); if ( png == NULL ) { Sys_Printf( "WARNING: Unable to create PNG read struct\n" ); return; } info = png_create_info_struct( png ); if ( info == NULL ) { Sys_Printf( "WARNING: Unable to create PNG info struct\n" ); png_destroy_read_struct( &png, NULL, NULL ); return; } end = png_create_info_struct( png ); if ( end == NULL ) { Sys_Printf( "WARNING: Unable to create PNG end info struct\n" ); png_destroy_read_struct( &png, &info, NULL ); return; } /* set read callback */ pb.buffer = buffer; pb.size = size; pb.offset = 0; png_set_read_fn( png, &pb, PNGReadData ); //png->io_ptr = &pb; /* hack! */ /* set error longjmp */ if ( setjmp( png_jmpbuf(png) ) ) { Sys_Printf( "WARNING: An error occurred reading PNG image\n" ); png_destroy_read_struct( &png, &info, &end ); return; } /* fixme: add proper i/o stuff here */ /* read png info */ png_read_info( png, info ); /* read image header chunk */ png_get_IHDR( png, info, &w, &h, &bitDepth, &colorType, NULL, NULL, NULL ); /* the following will probably bork on certain types of png images, but hey... */ /* force indexed/gray/trans chunk to rgb */ if ( ( colorType == PNG_COLOR_TYPE_PALETTE && bitDepth <= 8 ) || ( colorType == PNG_COLOR_TYPE_GRAY && bitDepth <= 8 ) || png_get_valid( png, info, PNG_INFO_tRNS ) ) { png_set_expand( png ); } /* strip 16bpc -> 8bpc */ if ( bitDepth == 16 ) { png_set_strip_16( png ); } /* pad rgb to rgba */ if ( bitDepth == 8 && colorType == PNG_COLOR_TYPE_RGB ) { png_set_filler( png, 255, PNG_FILLER_AFTER ); } /* create image pixel buffer */ *width = w; *height = h; *pixels = safe_malloc( w * h * 4 ); /* create row pointers */ rowPointers = safe_malloc( h * sizeof( byte* ) ); for ( i = 0; i < h; i++ ) rowPointers[ i ] = *pixels + ( i * w * 4 ); /* read the png */ png_read_image( png, rowPointers ); /* clean up */ free( rowPointers ); png_destroy_read_struct( &png, &info, &end ); }
//--------------------------------------------------------------------------- void __fastcall TDeePNG::LoadFromStream(Classes::TStream * Stream) { // LoadFromStream png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_infop end_info = NULL; png_bytep *row_pointers = NULL; BYTE *image = NULL; png_uint_32 i; try { // create png_struct png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)this, DeePNG_error, DeePNG_warning, (png_voidp)this, DeePNG_malloc, DeePNG_free); // set read_chunk_callback png_set_read_user_chunk_fn(png_ptr, reinterpret_cast<void*>(this), PNG_read_chunk_callback); png_set_keep_unknown_chunks(png_ptr, 2, NULL, 0); // keep only if safe-to-copy chunks, for all unknown chunks // create png_info info_ptr = png_create_info_struct(png_ptr); // create end_info end_info = png_create_info_struct(png_ptr); // set stream input functions png_set_read_fn(png_ptr, (voidp)Stream, DeePNG_read_data); // set read_row_callback png_set_read_status_fn(png_ptr, DeePNG_read_row_callback); // call png_read_info png_read_info(png_ptr, info_ptr); // retrieve IHDR png_uint_32 width, height; int bit_depth, color_type, interlace_type, compression_type, filter_type; png_get_IHDR(png_ptr,info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type); // expand palletted image which has transparent color, to 32bpp if (png_get_valid(png_ptr, info_ptr,PNG_INFO_tRNS)) { png_set_expand(png_ptr); color_type=PNG_COLOR_TYPE_RGB_ALPHA; } // analyse IHDR ( color_type ) switch(color_type) { case PNG_COLOR_TYPE_GRAY_ALPHA: PixelFormat=pf32bit; break; case PNG_COLOR_TYPE_GRAY: // w/b SetGrayscalePalette(this,bit_depth); break; case PNG_COLOR_TYPE_PALETTE: SetColorDepth(this,bit_depth); break; case PNG_COLOR_TYPE_RGB_ALPHA: PixelFormat=pf32bit; break; case PNG_COLOR_TYPE_RGB: PixelFormat=pf24bit; break; default: throw EDeePNG("EDeePNG : Non-supported color type."); } // retrieve offset information png_int_32 offset_x, offset_y; int offset_unit_type; if(png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, &offset_unit_type)) { ofs_x = offset_x; ofs_y = offset_y; ofs_unit = offset_unit_type; ofs_set = true; } else { ofs_set = false; } // check size if(width>=65536 || height>=65536) { throw EDeePNG("EDeePNG : Too large image size."); } // retrieve palette if(color_type == PNG_COLOR_TYPE_PALETTE) { int num_palette; png_color *palette = NULL; png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); int i; #pragma pack(push, 1) struct { WORD palVersion; WORD palNumEntries; PALETTEENTRY entry[256]; } pal; #pragma pack(pop) pal.palVersion = 0x300; pal.palNumEntries = num_palette; for(i = 0; i < num_palette; i++) { pal.entry[i].peRed = palette[i].red; pal.entry[i].peGreen = palette[i].green; pal.entry[i].peBlue = palette[i].blue; pal.entry[i].peFlags = 0; } Palette = CreatePalette((const LOGPALETTE*)&pal); } // collapse 16bit precision data to 8bit if(bit_depth == 16) png_set_strip_16(png_ptr); // change color component order if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) png_set_bgr(png_ptr); // call png_read_update_info ... png_read_update_info(png_ptr, info_ptr); // set size Width=width, Height=height; // allocate memory for row_pointers row_pointers = new png_bytep[height]; png_uint_32 rowbytes = png_get_rowbytes(png_ptr, info_ptr); image = new BYTE[rowbytes*height]; for(i = 0; i < height; i++) { row_pointers[i] = image + i*rowbytes; } // load image png_read_image(png_ptr, row_pointers); // finish loading image png_read_end(png_ptr, info_ptr); // set image to ScanLines BYTE *imageptr = image; if(color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { // IA IA IA .... for(i = 0; i < height; i++) { BYTE *scanptr = (BYTE*)ScanLine[i]; png_uint_32 j; for(j = 0; j < width; j++) { BYTE i = *(imageptr++); scanptr[0] = i; scanptr[1] = i; scanptr[2] = i; scanptr[3] = *(imageptr++); scanptr += 4; } } } else { // intact copy for(i = 0; i < height; i++) { BYTE *scanptr = (BYTE*)ScanLine[i]; memcpy(scanptr, imageptr, rowbytes); imageptr += rowbytes; } } } catch(...) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); if(row_pointers) delete [] row_pointers; if(image) delete [] image; throw; } png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); if(row_pointers) delete [] row_pointers; if(image) delete [] image; }
twin_pixmap_t *twin_png_to_pixmap(const char *filepath, twin_format_t fmt) { uint8_t signature[8]; int fd, i, rb = 0; size_t n; png_structp png = NULL; png_infop info = NULL; twin_pixmap_t *pix = NULL; twin_png_priv_t priv; png_uint_32 width, height; int depth, ctype, interlace; png_bytep *rowp = NULL; DEBUG("png read for %s, format=%d\n", filepath, fmt); fd = open(filepath, O_RDONLY); if (fd < 0) goto fail; DEBUG("checking signature...\n"); n = read(fd, signature, 8); if (png_sig_cmp(signature, 0, n) != 0) goto fail_close; DEBUG("creating libpng structures...\n"); png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png == NULL) goto fail_close; info = png_create_info_struct(png); if (info == NULL) goto fail_free; if (setjmp(png_jmpbuf(png))) { DEBUG("* error callback *\n"); if (pix) twin_pixmap_destroy(pix); pix = NULL; goto fail_free; } priv.fd = fd; png_set_read_fn(png, &priv, twin_png_read_fn); png_set_sig_bytes(png, n); DEBUG("reading picture infos ...\n"); png_read_info(png, info); png_get_IHDR(png, info, &width, &height, &depth, &ctype, &interlace, int_p_NULL, int_p_NULL); DEBUG(" 1- size/depth/ctype/int = %ldx%ld/%d/%d/%d\n", width, height, depth, ctype, interlace); if (depth == 16) png_set_strip_16(png); if (ctype == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); if (ctype == PNG_COLOR_TYPE_GRAY && depth < 8) png_set_gray_1_2_4_to_8(png); if (png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); png_get_IHDR(png, info, &width, &height, &depth, &ctype, &interlace, int_p_NULL, int_p_NULL); DEBUG(" 2- size/depth/ctype/int = %ldx%ld/%d/%d/%d\n", width, height, depth, ctype, interlace); switch(fmt) { case TWIN_A8: if (ctype != PNG_COLOR_TYPE_GRAY || depth != 8) goto fail_free; rb = width; break; case TWIN_RGB16: /* unsupported for now */ goto fail_free; case TWIN_ARGB32: if (ctype == PNG_COLOR_TYPE_RGB) png_set_filler(png, 0xff, PNG_FILLER_BEFORE); if (ctype == PNG_COLOR_TYPE_RGB_ALPHA) png_set_swap_alpha(png); if (ctype == PNG_COLOR_TYPE_GRAY || ctype == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); png_get_IHDR(png, info, &width, &height, &depth, &ctype, &interlace, int_p_NULL, int_p_NULL); DEBUG(" 3- size/depth/ctype/int = %ldx%ld/%d/%d/%d\n", width, height, depth, ctype, interlace); if (depth != 8) goto fail_free; rb = width * 4; break; } DEBUG(" rowbytes = %d\n", rb); DEBUG("preparing pixmap & row pointer array...\n"); rowp = malloc(height * sizeof(png_bytep)); if (rowp == NULL) goto fail_free; pix = twin_pixmap_create(fmt, width, height); if (pix == NULL) goto fail_free; for (i = 0; i < height; i++) rowp[i] = pix->p.b + rb * i; DEBUG("reading image...\n"); png_read_image(png, rowp); png_read_end(png, NULL); if (fmt == TWIN_ARGB32) twin_premultiply_alpha(pix); fail_free: if (rowp) free(rowp); png_destroy_read_struct(&png, &info, png_infopp_NULL); fail_close: close(fd); fail: return pix; }
//------------------------------------------------------------------------------- Status Image::loadAsPNG(BYTE* data) { png_byte header[8]; png_structp pngPtr = NULL; png_infop infoPtr = NULL; png_bytep* rowPtrs = NULL; png_int_32 rowSize; bool transparency; ///////////////////////////////////////////////: // Check the header signature memcpy(header, data, sizeof(header)); if (png_sig_cmp(header, 0, 8) != 0) goto ERROR; pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, png_error_fn, // error callback png_warning_fn); // warning callback if (!pngPtr) goto ERROR; infoPtr = png_create_info_struct(pngPtr); if (!infoPtr) goto ERROR; if (setjmp(png_jmpbuf(pngPtr))) goto ERROR; //////////////////////////////////////////////////////////////////////// // Create the read structure and set the read function from a memory pointer ByteBuffer bb; bb.offset = 8; //sig bb.data = data; png_set_read_fn(pngPtr, &bb, memoryReadCallback); //tell libpng we already read the signature png_set_sig_bytes(pngPtr, 8); png_read_info(pngPtr, infoPtr); png_int_32 depth, colorType; png_uint_32 width, height; png_get_IHDR(pngPtr, infoPtr, &width, &height, &depth, &colorType, NULL, NULL, NULL); mWidth = width; mHeight = height; // Creates a full alpha channel if transparency is encoded as // an array of palette entries or a single transparent color. transparency = false; if (png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(pngPtr); transparency = true; } // Expands PNG with less than 8bits per channel to 8bits. if (depth < 8) { png_set_packing(pngPtr); } // Shrinks PNG with 16bits per color channel down to 8bits. else if (depth == 16){ png_set_strip_16(pngPtr); } // Indicates that image needs conversion to RGBA if needed. switch (colorType){ case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(pngPtr); if (transparency) { mFormat = GL_RGBA; mBytesPerPixel = 4; } else { mFormat = GL_RGB; mBytesPerPixel = 3; } break; case PNG_COLOR_TYPE_RGB: if (transparency) { mFormat = GL_RGBA; mBytesPerPixel = 4; } else { mFormat = GL_RGB; mBytesPerPixel = 3; } break; case PNG_COLOR_TYPE_RGBA: if (transparency) { mFormat = GL_RGBA; mBytesPerPixel = 4; } else { mFormat = GL_RGB; mBytesPerPixel = 3; } break; case PNG_COLOR_TYPE_GRAY: png_set_expand_gray_1_2_4_to_8(pngPtr); mFormat = transparency ? GL_LUMINANCE_ALPHA : GL_LUMINANCE; if (transparency) { mFormat = GL_LUMINANCE_ALPHA; mBytesPerPixel = 2; } else { mFormat = GL_LUMINANCE; mBytesPerPixel = 1; } break; case PNG_COLOR_TYPE_GA: png_set_expand_gray_1_2_4_to_8(pngPtr); if (transparency) { mFormat = GL_LUMINANCE_ALPHA; mBytesPerPixel = 2; } else { mFormat = GL_LUMINANCE; mBytesPerPixel = 1; } break; default: assert(false); break; } png_read_update_info(pngPtr, infoPtr); rowSize = png_get_rowbytes(pngPtr, infoPtr); if(rowSize <= 0) goto ERROR; mPixels = new BYTE[rowSize * height]; if(!mPixels) goto ERROR; rowPtrs = new png_bytep[height]; if(!rowPtrs) goto ERROR; for(U32 i = 0; i < height; ++i){ rowPtrs[height - (i + 1)] = mPixels + i * rowSize; } png_read_image(pngPtr, rowPtrs); png_destroy_read_struct(&pngPtr, &infoPtr, NULL); delete[] rowPtrs; return STATUS_OK; ERROR: Log::error(TAG, "Error while reading PNG data"); delete[] rowPtrs; delete[] mPixels; if(pngPtr != NULL){ png_infop* infoPtrP = infoPtr != NULL ? &infoPtr : NULL; png_destroy_read_struct(&pngPtr, infoPtrP, NULL); } return throwException(TAG, ExceptionType::INVALID_FILE, "unknown error while reading PNG data"); }
// load in the image data IImage* CImageLoaderPng::loadImage(io::IReadFile* file) const { #ifdef _IRR_COMPILE_WITH_LIBPNG_ if (!file) return 0; video::IImage* image = 0; //Used to point to image rows u8** RowPointers = 0; png_byte buffer[8]; // Read the first few bytes of the PNG file if( file->read(buffer, 8) != 8 ) { os::Printer::log("LOAD PNG: can't read file\n", file->getFileName(), ELL_ERROR); return 0; } // Check if it really is a PNG file if( png_sig_cmp(buffer, 0, 8) ) { os::Printer::log("LOAD PNG: not really a png\n", file->getFileName(), ELL_ERROR); return 0; } // Allocate the png read struct png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, (png_error_ptr)png_cpexcept_error, (png_error_ptr)png_cpexcept_warn); 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); delete [] RowPointers; return 0; } // changed by zola so we don't need to have public FILE pointers png_set_read_fn(png_ptr, file, user_read_data_fcn); png_set_sig_bytes(png_ptr, 8); // Tell png that we read the signature png_read_info(png_ptr, info_ptr); // Read the info section of the png file u32 Width; u32 Height; s32 BitDepth; s32 ColorType; { // Use temporary variables to avoid passing casted pointers png_uint_32 w,h; // Extract info png_get_IHDR(png_ptr, info_ptr, &w, &h, &BitDepth, &ColorType, NULL, NULL, NULL); Width=w; Height=h; } // Convert palette color to true color if (ColorType==PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); // Convert low bit colors to 8 bit colors if (BitDepth < 8) { if (ColorType==PNG_COLOR_TYPE_GRAY || ColorType==PNG_COLOR_TYPE_GRAY_ALPHA) png_set_expand_gray_1_2_4_to_8(png_ptr); else png_set_packing(png_ptr); } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); // Convert high bit colors to 8 bit colors if (BitDepth == 16) png_set_strip_16(png_ptr); // Convert gray color to true color if (ColorType==PNG_COLOR_TYPE_GRAY || ColorType==PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); int intent; const double screen_gamma = 2.2; if (png_get_sRGB(png_ptr, info_ptr, &intent)) png_set_gamma(png_ptr, screen_gamma, 0.45455); else { double image_gamma; if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) png_set_gamma(png_ptr, screen_gamma, image_gamma); else png_set_gamma(png_ptr, screen_gamma, 0.45455); } // Update the changes in between, as we need to get the new color type // for proper processing of the RGBA type png_read_update_info(png_ptr, info_ptr); { // Use temporary variables to avoid passing casted pointers png_uint_32 w,h; // Extract info png_get_IHDR(png_ptr, info_ptr, &w, &h, &BitDepth, &ColorType, NULL, NULL, NULL); Width=w; Height=h; } // Convert RGBA to BGRA if (ColorType==PNG_COLOR_TYPE_RGB_ALPHA) { #ifdef __BIG_ENDIAN__ png_set_swap_alpha(png_ptr); #else png_set_bgr(png_ptr); #endif } // Create the image structure to be filled by png data if (ColorType==PNG_COLOR_TYPE_RGB_ALPHA) image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(Width, Height)); else image = new CImage(ECF_R8G8B8, core::dimension2d<u32>(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->getData(); 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; 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; png_destroy_read_struct(&png_ptr,&info_ptr, 0); // Clean up memory return image; #else return 0; #endif // _IRR_COMPILE_WITH_LIBPNG_ }
static void png_info_callback(png_structp png_ptr, png_infop info_ptr) { int bit_depth, color_type, intent; double gamma; int bytes_per_pixel=3; struct cached_image *cimg; cimg=global_cimg; bit_depth=png_get_bit_depth(png_ptr, info_ptr); color_type=png_get_color_type(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); /* Legacy version of png_set_tRNS_to_alpha(png_ptr); */ bytes_per_pixel++; } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); if (bit_depth==16){ #ifndef REPACK_16 #ifdef C_LITTLE_ENDIAN /* We use native endianity only if unsigned short is 2-byte * because otherwise we have to reassemble the buffer so we * will leave in the libpng-native big endian. */ png_set_swap(png_ptr); #endif /* #ifdef C_LITTLE_ENDIAN */ #endif /* #ifndef REPACK_16 */ bytes_per_pixel*=sizeof(unsigned short); } png_set_interlace_handling(png_ptr); if (color_type==PNG_COLOR_TYPE_RGB_ALPHA ||color_type==PNG_COLOR_TYPE_GRAY_ALPHA){ if (bytes_per_pixel==3 ||bytes_per_pixel==3*sizeof(unsigned short)) bytes_per_pixel=4*bytes_per_pixel/3; } cimg->width=png_get_image_width(png_ptr,info_ptr); cimg->height=png_get_image_height(png_ptr,info_ptr); cimg->buffer_bytes_per_pixel=bytes_per_pixel; if (png_get_sRGB(png_ptr, info_ptr, &intent)){ gamma=sRGB_gamma; } else { if (!png_get_gAMA(png_ptr, info_ptr, &gamma)){ gamma=sRGB_gamma; } } cimg->red_gamma=gamma; cimg->green_gamma=gamma; cimg->blue_gamma=gamma; png_read_update_info(png_ptr,info_ptr); cimg->strip_optimized=0; if (header_dimensions_known(cimg)) img_my_png_error(png_ptr, "bad image size"); }
void PNGFile::_Load(std::istream &Stream) { //Leemos y verificamos la firma del archivo para asegurarnos que sea un png png_bytep pFirma = new png_byte[8]; Stream.read((char*)pFirma, sizeof(png_byte)*8); if( png_sig_cmp(pFirma, 0, 8) != 0 ) throw std::exception();//"El archivo cargado no es un png"); delete[] pFirma; m_pPNGReadStruct = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if ( m_pPNGReadStruct == NULL )//Si fallo la creacion del struct de lectura del png throw std::exception();//"No se pudo crear el struct de lectura de png"); //Establecemos la funcion/callback que usare LibPNG para leer los datos png_set_read_fn(m_pPNGReadStruct,(png_voidp)&Stream, leerDatosfn); //Intentamos crear el encabezado del archivo png m_pHeader = png_create_info_struct(m_pPNGReadStruct); if ( m_pHeader == NULL ) { png_destroy_read_struct(&m_pPNGReadStruct, (png_infopp)0, (png_infopp)0);//liberamos el png throw std::exception();//"No se pudo crear el encabezado del archivo png"); } //Apuntara a cada fila de la imagen en m_EspacioColores... ver mas abajo una explicacion mas detallada png_bytep* ArregloFilas = NULL; //Informamos que si ocurre un error leyendo el archivo salte a este if if (setjmp(png_jmpbuf(m_pPNGReadStruct))) { png_destroy_read_struct(&m_pPNGReadStruct, &m_pHeader,(png_infopp)0);//liberamos el png y el encabezado if (ArregloFilas != NULL) delete [] ArregloFilas; if (m_ArregloColores != NULL) delete [] m_ArregloColores; throw std::exception();//"Sucedio un error leyendo el archivo png"); } //Avisamos a libpng que la firma ya fue leida y que lea el encabezado png_set_sig_bytes(m_pPNGReadStruct, 8); //Leemos el encabezado del png png_read_info(m_pPNGReadStruct, m_pHeader); //Leemos las dimensiones de la imagen del encabezado m_Width = png_get_image_width (m_pPNGReadStruct, m_pHeader); m_Height = png_get_image_height(m_pPNGReadStruct, m_pHeader); //Bits por canal de la imagen(NO POR PIXEL, SINO POR CANAL... EN GENERAL 1 PIXEL TIENE MUCHOS CANALES) png_uint_32 bitdepth = png_get_bit_depth(m_pPNGReadStruct, m_pHeader); //Numero de canales de la imagen png_uint_32 channels = png_get_channels(m_pPNGReadStruct, m_pHeader); //Tipo de espacio de colores... luego lo convertiremos a m_EspacioColores png_uint_32 color_type = png_get_color_type(m_pPNGReadStruct, m_pHeader); //Si el formato de la imagen no es R8_G8_B8_ o R8_G8_B8_A8 intentamos convertirla a //estos usando funciones de LibPNG switch (color_type) { case PNG_COLOR_TYPE_RGB: m_EspacioColores = ImageFile::R8_G8_B8; break; case PNG_COLOR_TYPE_RGBA: m_EspacioColores = ImageFile::R8_G8_B8_A8; break; case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(m_pPNGReadStruct); m_EspacioColores = ImageFile::R8_G8_B8; channels = 3;//ahora tendremos 3 canales break; case PNG_COLOR_TYPE_GRAY: png_set_gray_to_rgb(m_pPNGReadStruct); m_EspacioColores = ImageFile::R8_G8_B8; bitdepth = 8; channels = 3;//ahora tendremos 3 canales break; default: throw std::exception();//"La implementacion de PNGFile no soporta el espacio de colores de la imagen que se esta cargando"); } //Si la imagen tiene transparencia la convertimos al canal alpha if (png_get_valid(m_pPNGReadStruct, m_pHeader, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(m_pPNGReadStruct); channels+=1;//Un canal mas } //Si cada canal tiene 16 bits de profundidad lo convertimos a 8 bits //ya que nuestros formatos son de 8 bits de profundidad if( bitdepth == 16 ) png_set_strip_16(m_pPNGReadStruct); //LibPNG lee los datos de color por filas de la imagen //Para hacerlo requiere que le pasemos un arreglo de punteros a donde se almacenara cada //fila de la imagen ArregloFilas = new png_bytep[m_Height]; //Almacenamos el buffer donde se almacenara la imagen leida(ArregloFilas apuntara a direciones dentro de este buffer) m_ArregloColores = new unsigned char[m_Width * m_Height * (bitdepth * channels / 8)]; //El tamaño que ocupa una fila de la imagen const unsigned int rowTotSize = m_Width * bitdepth * channels / 8; //Ahora apuntamos los punteros de ArregloFilas a las direciones de m_ArregloColores //donde cada elemento de ArregloFilas es la dir de una fila de la imagen for (unsigned int i = 0; i < m_Height; i++) ArregloFilas[i] = (png_bytep)m_ArregloColores + i*rowTotSize; //Aca leemos los datos de la imagen del archivo //Alamcena los cada fila en las direciones señaladas por ArregloFilas //que a su vez apuntan dentro de m_ArregloColores... lo cual significa //que luego de esto m_ArregloColores tendra los datos de la imagen como los deseamos png_read_image(m_pPNGReadStruct, ArregloFilas); //Limpiamos el arreglo de punteros a filas(NO LOS DATOS SINO SOLO LOS PUNTEROS) delete[] (png_bytep)ArregloFilas; png_destroy_read_struct(&m_pPNGReadStruct, &m_pHeader,(png_infopp)0);//liberamos el png y el encabezado if( Stream.bad() || Stream.fail() || Stream.eof() ) throw std::exception();//"La carga del archivo bmp tuvo errores"); }
static GrTextureFormat_t PNG_Load(const char *filename, int *w, int *h, GLPatch_t *grpatch) { png_structp png_ptr; png_infop png_info_ptr; png_uint_32 width, height; int bit_depth, color_type; #ifdef PNG_SETJMP_SUPPORTED #ifdef USE_FAR_KEYWORD jmp_buf jmpbuf; #endif #endif png_FILE_p png_FILE; char *pngfilename = va("md2/%s", filename); FIL_ForceExtension(pngfilename, ".png"); png_FILE = fopen(pngfilename, "rb"); if (!png_FILE) { //CONS_Debug(DBG_RENDER, "M_SavePNG: Error on opening %s for loading\n", filename); return 0; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, PNG_error, PNG_warn); if (!png_ptr) { CONS_Debug(DBG_RENDER, "PNG_Load: Error on initialize libpng\n"); fclose(png_FILE); return 0; } png_info_ptr = png_create_info_struct(png_ptr); if (!png_info_ptr) { CONS_Debug(DBG_RENDER, "PNG_Load: Error on allocate for libpng\n"); png_destroy_read_struct(&png_ptr, NULL, NULL); fclose(png_FILE); return 0; } #ifdef USE_FAR_KEYWORD if (setjmp(jmpbuf)) #else if (setjmp(png_jmpbuf(png_ptr))) #endif { //CONS_Debug(DBG_RENDER, "libpng load error on %s\n", filename); png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL); fclose(png_FILE); Z_Free(grpatch->mipmap.grInfo.data); return 0; } #ifdef USE_FAR_KEYWORD png_memcpy(png_jmpbuf(png_ptr), jmpbuf, sizeof jmp_buf); #endif png_init_io(png_ptr, png_FILE); #ifdef PNG_SET_USER_LIMITS_SUPPORTED png_set_user_limits(png_ptr, 2048, 2048); #endif png_read_info(png_ptr, png_info_ptr); png_get_IHDR(png_ptr, png_info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); 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); else if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); else if (color_type != PNG_COLOR_TYPE_RGB_ALPHA && color_type != PNG_COLOR_TYPE_GRAY_ALPHA) { #if PNG_LIBPNG_VER < 10207 png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); #else png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER); #endif } png_read_update_info(png_ptr, png_info_ptr); { png_uint_32 i, pitch = png_get_rowbytes(png_ptr, png_info_ptr); png_bytep PNG_image = Z_Malloc(pitch*height, PU_HWRCACHE, &grpatch->mipmap.grInfo.data); png_bytepp row_pointers = png_malloc(png_ptr, height * sizeof (png_bytep)); for (i = 0; i < height; i++) row_pointers[i] = PNG_image + i*pitch; png_read_image(png_ptr, row_pointers); png_free(png_ptr, (png_voidp)row_pointers); } png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL); fclose(png_FILE); *w = (int)width; *h = (int)height; return GR_RGBA; }