RImage *RLoadPNG(RContext *context, const char *file) { char *tmp; RImage *image = NULL; FILE *f; png_structp png; png_infop pinfo, einfo; png_color_16p bkcolor; int alpha; int x, y, i; double gamma, sgamma; png_uint_32 width, height; int depth, junk, color_type; png_bytep *png_rows; unsigned char *ptr; f = fopen(file, "rb"); if (!f) { RErrorCode = RERR_OPEN; return NULL; } png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, (png_error_ptr) NULL, (png_error_ptr) NULL); if (!png) { RErrorCode = RERR_NOMEMORY; fclose(f); return NULL; } pinfo = png_create_info_struct(png); if (!pinfo) { RErrorCode = RERR_NOMEMORY; fclose(f); png_destroy_read_struct(&png, NULL, NULL); return NULL; } einfo = png_create_info_struct(png); if (!einfo) { RErrorCode = RERR_NOMEMORY; fclose(f); png_destroy_read_struct(&png, &pinfo, NULL); return NULL; } RErrorCode = RERR_INTERNAL; #if PNG_LIBPNG_VER - 0 < 10400 if (setjmp(png->jmpbuf)) { #else if (setjmp(png_jmpbuf(png))) { #endif fclose(f); png_destroy_read_struct(&png, &pinfo, &einfo); if (image) RReleaseImage(image); return NULL; } png_init_io(png, f); png_read_info(png, pinfo); png_get_IHDR(png, pinfo, &width, &height, &depth, &color_type, &junk, &junk, &junk); /* sanity check */ if (width < 1 || height < 1) { fclose(f); png_destroy_read_struct(&png, &pinfo, &einfo); RErrorCode = RERR_BADIMAGEFILE; return NULL; } /* check for an alpha channel */ if (png_get_valid(png, pinfo, PNG_INFO_tRNS)) alpha = True; else alpha = (color_type & PNG_COLOR_MASK_ALPHA); /* allocate RImage */ image = RCreateImage(width, height, alpha); if (!image) { fclose(f); png_destroy_read_struct(&png, &pinfo, &einfo); return NULL; } /* normalize to 8bpp with alpha channel */ if (color_type == PNG_COLOR_TYPE_PALETTE && depth <= 8) png_set_expand(png); if (color_type == PNG_COLOR_TYPE_GRAY && depth <= 8) png_set_expand(png); if (png_get_valid(png, pinfo, PNG_INFO_tRNS)) png_set_expand(png); if (depth == 16) png_set_strip_16(png); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); /* set gamma correction */ if ((context->attribs->flags & RC_GammaCorrection) && context->depth != 8) { sgamma = (context->attribs->rgamma + context->attribs->ggamma + context->attribs->bgamma) / 3; } else if ((tmp = getenv("DISPLAY_GAMMA")) != NULL) { sgamma = atof(tmp); if (sgamma < 1.0E-3) sgamma = 1; } else { /* blah */ sgamma = 2.2; } if (png_get_gAMA(png, pinfo, &gamma)) png_set_gamma(png, sgamma, gamma); else png_set_gamma(png, sgamma, 0.45); /* do the transforms */ png_read_update_info(png, pinfo); /* set background color */ if (png_get_bKGD(png, pinfo, &bkcolor)) { image->background.red = bkcolor->red >> 8; image->background.green = bkcolor->green >> 8; image->background.blue = bkcolor->blue >> 8; } png_rows = calloc(height, sizeof(char *)); if (!png_rows) { RErrorCode = RERR_NOMEMORY; fclose(f); RReleaseImage(image); png_destroy_read_struct(&png, &pinfo, &einfo); return NULL; } for (y = 0; y < height; y++) { png_rows[y] = malloc(png_get_rowbytes(png, pinfo)); if (!png_rows[y]) { RErrorCode = RERR_NOMEMORY; fclose(f); RReleaseImage(image); png_destroy_read_struct(&png, &pinfo, &einfo); while (y-- > 0) if (png_rows[y]) free(png_rows[y]); free(png_rows); return NULL; } } /* read data */ png_read_image(png, png_rows); png_read_end(png, einfo); png_destroy_read_struct(&png, &pinfo, &einfo); fclose(f); ptr = image->data; /* convert to RImage */ if (alpha) { for (y = 0; y < height; y++) { for (x = 0, i = width * 4; x < i; x++, ptr++) { *ptr = *(png_rows[y] + x); } } } else { for (y = 0; y < height; y++) { for (x = 0, i = width * 3; x < i; x++, ptr++) { *ptr = *(png_rows[y] + x); } } } for (y = 0; y < height; y++) if (png_rows[y]) free(png_rows[y]); free(png_rows); return image; }
void PNGImageDecoder::headerAvailable() { png_structp png = m_reader->pngPtr(); png_infop info = m_reader->infoPtr(); png_uint_32 width = png->width; png_uint_32 height = png->height; // Protect against large images. if (png->width > cMaxPNGSize || png->height > cMaxPNGSize) { longjmp(JMPBUF(png), 1); return; } // We can fill in the size now that the header is available. Avoid memory // corruption issues by neutering setFailed() during this call; if we don't // do this, failures will cause |m_reader| to be deleted, and our jmpbuf // will cease to exist. Note that we'll still properly set the failure flag // in this case as soon as we longjmp(). m_doNothingOnFailure = true; bool result = setSize(width, height); m_doNothingOnFailure = false; if (!result) { longjmp(JMPBUF(png), 1); return; } int bitDepth, colorType, interlaceType, compressionType, filterType, channels; png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType, &interlaceType, &compressionType, &filterType); if ((colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_RGB_ALPHA) && !m_ignoreGammaAndColorProfile) { // We currently support color profiles only for RGB and RGBA PNGs. Supporting // color profiles for gray-scale images is slightly tricky, at least using the // CoreGraphics ICC library, because we expand gray-scale images to RGB but we // don't similarly transform the color profile. We'd either need to transform // the color profile or we'd need to decode into a gray-scale image buffer and // hand that to CoreGraphics. m_colorProfile = readColorProfile(png, info); } // The options we set here match what Mozilla does. // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA. if (colorType == PNG_COLOR_TYPE_PALETTE || (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8)) png_set_expand(png); png_bytep trns = 0; int trnsCount = 0; if (png_get_valid(png, info, PNG_INFO_tRNS)) { png_get_tRNS(png, info, &trns, &trnsCount, 0); png_set_expand(png); } if (bitDepth == 16) png_set_strip_16(png); if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); // Deal with gamma and keep it under our control. double gamma; if (!m_ignoreGammaAndColorProfile && png_get_gAMA(png, info, &gamma)) { if ((gamma <= 0.0) || (gamma > cMaxGamma)) { gamma = cInverseGamma; png_set_gAMA(png, info, gamma); } png_set_gamma(png, cDefaultGamma, gamma); } else png_set_gamma(png, cDefaultGamma, cInverseGamma); // Tell libpng to send us rows for interlaced pngs. if (interlaceType == PNG_INTERLACE_ADAM7) png_set_interlace_handling(png); // Update our info now. png_read_update_info(png, info); channels = png_get_channels(png, info); ASSERT(channels == 3 || channels == 4); m_reader->setHasAlpha(channels == 4); if (m_reader->decodingSizeOnly()) { // If we only needed the size, halt the reader. m_reader->setReadOffset(m_reader->currentBufferSize() - png->buffer_size); png->buffer_size = 0; } }
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; header_dimensions_known(cimg); }
int int_png_load(const char *name, unsigned char **buffer, int* xp, int* yp, int* bpp, bool alpha) { static const png_color_16 my_background = {0, 0, 0, 0, 0}; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; unsigned int i; int bit_depth, color_type, interlace_type, number_passes, pass, int_bpp; png_byte * fbptr; FILE * fh; if(!(fh=fopen(name,"rb"))) return(FH_ERROR_FILE); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(png_ptr == NULL) { fclose(fh); return(FH_ERROR_FORMAT); } info_ptr = png_create_info_struct(png_ptr); if(info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); fclose(fh); return(FH_ERROR_FORMAT); } #if (PNG_LIBPNG_VER < 10500) if (setjmp(png_ptr->jmpbuf)) #else if (setjmp(png_jmpbuf(png_ptr))) #endif { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fh); return(FH_ERROR_FORMAT); } png_init_io(png_ptr,fh); 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 (alpha) { *bpp = png_get_channels(png_ptr, info_ptr); if ((*bpp != 4) || !(color_type & PNG_COLOR_MASK_ALPHA)) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fh); return fh_png_load(name, buffer, xp, yp); } // 24bit PNGs with alpha-channel int_bpp = 4; // png_set_swap_alpha(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); }else // All other PNGs { if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); png_set_background(png_ptr, (png_color_16*)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); /* other possibility for png_set_background: use png_get_bKGD */ } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); png_set_background(png_ptr, (png_color_16*)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); } /* this test does not trigger for 8bit-paletted PNGs with newer libpng (1.2.36 at least), but the data delivered is with alpha channel anyway, so always strip alpha for now */ #if PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR <= 2 && PNG_LIBPNG_VER_RELEASE < 36 if (color_type & PNG_COLOR_MASK_ALPHA) #endif png_set_strip_alpha(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); int_bpp = 3; } if (bit_depth == 16) png_set_strip_16(png_ptr); number_passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr,info_ptr); unsigned long rowbytes = png_get_rowbytes(png_ptr, info_ptr); if (width * int_bpp != rowbytes) { printf("[png.cpp]: Error processing %s - please report (including image).\n", name); printf(" width: %lu rowbytes: %lu\n", (unsigned long)width, (unsigned long)rowbytes); fclose(fh); return(FH_ERROR_FORMAT); } for (pass = 0; pass < number_passes; pass++) { fbptr = (png_byte *)(*buffer); for (i = 0; i < height; i++, fbptr += width * int_bpp) png_read_row(png_ptr, fbptr, NULL); } png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fh); return(FH_ERROR_OK); }
Bool readPng (const char *filename, char **data, unsigned int *width, unsigned int *height) { static const int PNG_SIG_SIZE = 8; unsigned char png_sig[PNG_SIG_SIZE]; FILE *file; int sig_bytes; png_struct *png; png_info *info; png_uint_32 png_width, png_height; int depth, color_type, interlace, i; unsigned int pixel_size; png_byte **row_pointers; file = fopen (filename, "r"); if (!file) { char *home, *imagedir; home = getenv ("HOME"); if (home) { imagedir = malloc (strlen (home) + strlen (HOME_IMAGEDIR) + strlen (filename) + 3); if (imagedir) { sprintf (imagedir, "%s/%s/%s", home, HOME_IMAGEDIR, filename); file = fopen (imagedir, "r"); free (imagedir); } } if (!file) { imagedir = malloc (strlen (IMAGEDIR) + strlen (filename) + 2); if (imagedir) { sprintf (imagedir, "%s/%s", IMAGEDIR, filename); file = fopen (imagedir, "r"); free (imagedir); } if (!file) return FALSE; } } sig_bytes = fread (png_sig, 1, PNG_SIG_SIZE, file); if (png_check_sig (png_sig, sig_bytes) == 0) { fclose (file); return FALSE; } png = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png) { fclose (file); return FALSE; } info = png_create_info_struct (png); if (info == NULL) { fclose (file); png_destroy_read_struct (&png, NULL, NULL); return FALSE; } png_init_io (png, file); png_set_sig_bytes (png, sig_bytes); png_read_info (png, info); png_get_IHDR (png, info, &png_width, &png_height, &depth, &color_type, &interlace, NULL, NULL); *width = png_width; *height = png_height; /* convert palette/gray image to rgb */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb (png); /* expand gray bit depth if needed */ if (color_type == PNG_COLOR_TYPE_GRAY && depth < 8) png_set_gray_1_2_4_to_8 (png); /* transform transparency to alpha */ if (png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha (png); if (depth == 16) png_set_strip_16 (png); if (depth < 8) png_set_packing (png); /* convert grayscale to RGB */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb (png); if (interlace != PNG_INTERLACE_NONE) png_set_interlace_handling (png); png_set_bgr (png); png_set_filler (png, 0xff, PNG_FILLER_AFTER); png_set_read_user_transform_fn (png, premultiplyData); png_read_update_info (png, info); pixel_size = 4; *data = (char *) malloc (png_width * png_height * pixel_size); if (*data == NULL) { fclose (file); return FALSE; } row_pointers = (png_byte **) malloc (png_height * sizeof (char *)); for (i=0; i < png_height; i++) row_pointers[i] = (png_byte *) (*data + i * png_width * pixel_size); png_read_image (png, row_pointers); png_read_end (png, info); free (row_pointers); fclose (file); png_destroy_read_struct (&png, &info, NULL); return TRUE; }
bool SkPNGImageDecoder::onDecodeInit(SkStream* sk_stream, png_structp *png_ptrp, png_infop *info_ptrp) { /* 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. */ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, sk_error_fn, NULL); // png_voidp user_error_ptr, user_error_fn, user_warning_fn); if (png_ptr == NULL) { return false; } *png_ptrp = png_ptr; /* Allocate/initialize the memory for image information. */ 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; } *info_ptrp = info_ptr; /* 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))) { return false; } /* If you are using replacement read functions, instead of calling * png_init_io() here you would call: */ png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn); png_set_seek_fn(png_ptr, sk_seek_fn); /* where user_io_ptr is a structure you want available to the callbacks */ /* If we have already read some of the signature */ // png_set_sig_bytes(png_ptr, 0 /* sig_read */ ); // hookup our peeker so we can see any user-chunks the caller may be interested in png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0); if (this->getPeeker()) { png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk); } /* 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); png_uint_32 origWidth, origHeight; int bit_depth, color_type, interlace_type; png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL); /* tell libpng to strip 16 bit/color files down to 8 bits/color */ if (bit_depth == 16) { png_set_strip_16(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). */ if (bit_depth < 8) { png_set_packing(png_ptr); } /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { png_set_gray_1_2_4_to_8(png_ptr); } /* Make a grayscale image into RGB. */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); } return true; }
void Image::LoadPNG(FILE *f, char *filename, Texture *tex) { png_structp png; png_infop pnginfo; byte ioBuffer[8192]; byte *raw; int filesize = SystemFileManager::FileLength(f); raw = (byte *) malloc(filesize + 1); if (raw == NULL) { Sys_Error("Out of memory to load PNG: %s\n", filename); return; } fread(raw, 1, filesize, f); fclose(f); if (!raw) { Con_Printf("Bad png file %s\n", filename); return; } if (png_sig_cmp(raw, 0, 4)) { free(raw); return; } png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!png) { free(raw); return; } pnginfo = png_create_info_struct(png); if (!pnginfo) { free(raw); png_destroy_read_struct(&png, &pnginfo, 0); return; } png_set_sig_bytes(png, 0/*sizeof( sig )*/); mypng_struct_create(); // creates the my_png struct my_png->tmpBuf = (char *) raw; //buf = whole file content my_png->tmpi = 0; png_set_read_fn(png, ioBuffer, fReadData); png_read_info(png, pnginfo); png_get_IHDR(png, pnginfo, &my_png->Width, &my_png->Height, &my_png->BitDepth, &my_png->ColorType, &my_png->Interlace, &my_png->Compression, &my_png->Filter); // ...removed bgColor code here... if (my_png->ColorType == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); if (my_png->ColorType == PNG_COLOR_TYPE_GRAY && my_png->BitDepth < 8) png_set_expand_gray_1_2_4_to_8(png); // Add alpha channel if present if (png_get_valid(png, pnginfo, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); // hax: expand 24bit to 32bit if (my_png->BitDepth == 8 && my_png->ColorType == PNG_COLOR_TYPE_RGB) png_set_filler(png, 255, PNG_FILLER_AFTER); if ((my_png->ColorType == PNG_COLOR_TYPE_GRAY) || (my_png->ColorType == PNG_COLOR_TYPE_GRAY_ALPHA)) { png_set_gray_to_rgb(png); png_set_add_alpha(png, 255, PNG_FILLER_AFTER); } if (my_png->BitDepth < 8) png_set_expand(png); // update the info structure png_read_update_info(png, pnginfo); my_png->FRowBytes = png_get_rowbytes(png, pnginfo); my_png->BytesPerPixel = png_get_channels(png, pnginfo); // DL Added 30/08/2000 InitializeDemData(); if ((my_png->Data) && (my_png->FRowPtrs)) png_read_image(png, (png_bytepp) my_png->FRowPtrs); png_read_end(png, pnginfo); // read last information chunks png_destroy_read_struct(&png, &pnginfo, 0); if (my_png->BitDepth == 8) { tex->width = my_png->Width; tex->height = my_png->Height; tex->bytesPerPixel = my_png->BytesPerPixel; tex->setData((byte *) my_png->Data); } else { Con_Printf("Bad png color depth: %s\n", filename); free(my_png->Data); } free(raw); mypng_struct_destroy(true); return; }
void PNGImageDecoder::headerAvailable() { png_structp png = reader()->pngPtr(); png_infop info = reader()->infoPtr(); png_uint_32 width = png->width; png_uint_32 height = png->height; // Protect against large images. if (png->width > cMaxPNGSize || png->height > cMaxPNGSize) { m_failed = true; longjmp(png->jmpbuf, 1); return; } // We can fill in the size now that the header is available. if (!m_sizeAvailable) { m_sizeAvailable = true; m_size = IntSize(width, height); } int bitDepth, colorType, interlaceType, compressionType, filterType, channels; png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType, &interlaceType, &compressionType, &filterType); // The options we set here match what Mozilla does. // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA. if (colorType == PNG_COLOR_TYPE_PALETTE || (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8)) png_set_expand(png); png_bytep trns = 0; int trnsCount = 0; if (png_get_valid(png, info, PNG_INFO_tRNS)) { png_get_tRNS(png, info, &trns, &trnsCount, 0); png_set_expand(png); } if (bitDepth == 16) png_set_strip_16(png); if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); // Deal with gamma and keep it under our control. double gamma; if (png_get_gAMA(png, info, &gamma)) { if ((gamma <= 0.0) || (gamma > cMaxGamma)) { gamma = cInverseGamma; png_set_gAMA(png, info, gamma); } png_set_gamma(png, cDefaultGamma, gamma); } else png_set_gamma(png, cDefaultGamma, cInverseGamma); // Tell libpng to send us rows for interlaced pngs. if (interlaceType == PNG_INTERLACE_ADAM7) png_set_interlace_handling(png); // Update our info now png_read_update_info(png, info); channels = png_get_channels(png, info); assert(channels == 3 || channels == 4); reader()->setHasAlpha(channels == 4); if (reader()->decodingSizeOnly()) { // If we only needed the size, halt the reader. reader()->setReadOffset(m_data->size() - png->buffer_size); png->buffer_size = 0; } }
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; } if (setjmp(png_ptr->jmpbuf)) { goto done; } png_ptr->io_ptr = io_ptr; png_ptr->read_data_fn = 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_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 png_load_img(img I) { unsigned char **p, **q; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int i, j, bit_depth, color_type, interlace_type; png_bytepp row_pointers; img_alloc(I); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { I->err = IE_HDRFORMAT; return 0; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); I->err = IE_HDRFORMAT; return 0; } rewind(I->fp); png_init_io(png_ptr, I->fp); png_read_info(png_ptr, info_ptr); /* Get image specific data */ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); /* Convert greyscale images to 8-bit RGB */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png_ptr); } png_set_gray_to_rgb(png_ptr); } /* Change paletted images to RGB */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); if (bit_depth < 8) png_set_expand(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); /* The gdk img widget appears to expect 8-bit RGB followed by a * filler byte. */ png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); /* Update the info structure after the transforms */ png_read_update_info(png_ptr, info_ptr); /* png_set_rows(png_ptr, info_ptr, row_pointers)*/ /* Allocate space before reading the image */ row_pointers = png_malloc(png_ptr, height * sizeof(png_bytep)); for (i = 0; i < height; i++) { row_pointers[i] = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); } /* Read in the image and copy it to the gdk img structure */ png_read_image(png_ptr, row_pointers); p = (unsigned char **)I->data; q = (unsigned char **)row_pointers; for (i = 0; i < height; i++) { for (j = 0; j < png_get_rowbytes(png_ptr, info_ptr); j++) { p[i][j] = q[i][j]; } } png_read_end(png_ptr, info_ptr); /* Clean up */ png_free(png_ptr, row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return 1; }
static int _png_get_hdr( wprint_image_info_t *image_info ) { unsigned char header[8]; memset(header, 0,sizeof(header)); int bit_depth, pixel_depth, number_of_passes; image_info->decoder_data.png_info.png_ptr = NULL; image_info->decoder_data.png_info.info_ptr = NULL; fseek(image_info->imgfile, 0, SEEK_SET); int header_size = fread(header, 1, sizeof(header), image_info->imgfile); image_info->wprint_ifc->debug(DBG_VERBOSE, "_png_get_hdr(): header_size: %d", header_size); int pngsig = png_sig_cmp(header, 0, sizeof(header)); if (pngsig) { image_info->wprint_ifc->debug(DBG_ERROR, "_png_get_hdr(): ERROR: not a PNG file"); return(ERROR); } image_info->wprint_ifc->debug(DBG_VERBOSE, "_png_get_hdr(): png_sig_cmp() returned %d", pngsig); image_info->wprint_ifc->debug(DBG_VERBOSE, "_png_get_hdr(): PNG_LIBPNG_VER_STRING: %s", PNG_LIBPNG_VER_STRING); /* initialize stuff */ image_info->decoder_data.png_info.png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); image_info->wprint_ifc->debug(DBG_VERBOSE, "_png_get_hdr(): png_create_read_struct() returned %d", image_info->decoder_data.png_info.png_ptr); if (!(image_info->decoder_data.png_info.png_ptr)) { image_info->wprint_ifc->debug(DBG_ERROR, "_png_get_hdr(): ERROR: png_create_read_struct failed"); return(ERROR); } image_info->decoder_data.png_info.info_ptr = png_create_info_struct(image_info->decoder_data.png_info.png_ptr); image_info->wprint_ifc->debug(DBG_VERBOSE, "_png_get_hdr(): png_create_info_struct() returned %d", image_info->decoder_data.png_info.info_ptr); if (!(image_info->decoder_data.png_info.info_ptr)) { image_info->wprint_ifc->debug(DBG_ERROR, "_png_get_hdr(): ERROR: png_create_info_struct failed"); return(ERROR); } if (setjmp(png_jmpbuf(image_info->decoder_data.png_info.png_ptr))) { image_info->wprint_ifc->debug(DBG_ERROR, "_png_get_hdr(): ERROR: invalid or corrupt PNG"); return(ERROR); } png_init_io(image_info->decoder_data.png_info.png_ptr, image_info->imgfile); png_set_sig_bytes(image_info->decoder_data.png_info.png_ptr, sizeof(header)); png_read_info(image_info->decoder_data.png_info.png_ptr, image_info->decoder_data.png_info.info_ptr); number_of_passes = png_set_interlace_handling(image_info->decoder_data.png_info.png_ptr); image_info->wprint_ifc->debug(DBG_VERBOSE, "_png_get_hdr(): png_set_interlace_handling() returned %d", number_of_passes); // setup background color as white png_color_16 bg_color; bg_color.index = 0; bg_color.red = (png_uint_16)-1; bg_color.green = (png_uint_16)-1; bg_color.blue = (png_uint_16)-1; bg_color.gray = (png_uint_16)-1; // blend alpha using white background color instead of stripping alpha channel png_set_background(image_info->decoder_data.png_info.png_ptr, &bg_color, PNG_BACKGROUND_GAMMA_FILE, 0, 1.0); // png_set_strip_alpha(image_info->decoder_data.png_info.png_ptr); png_set_expand(image_info->decoder_data.png_info.png_ptr); png_set_strip_16(image_info->decoder_data.png_info.png_ptr); png_set_gray_to_rgb(image_info->decoder_data.png_info.png_ptr); png_read_update_info(image_info->decoder_data.png_info.png_ptr, image_info->decoder_data.png_info.info_ptr); image_info->width = png_get_image_width(image_info->decoder_data.png_info.png_ptr, image_info->decoder_data.png_info.info_ptr); image_info->wprint_ifc->debug(DBG_VERBOSE, "_png_get_hdr(): png_get_image_width() returned %d", image_info->width); image_info->height = png_get_image_height(image_info->decoder_data.png_info.png_ptr, image_info->decoder_data.png_info.info_ptr); image_info->wprint_ifc->debug(DBG_VERBOSE, "_png_get_hdr(): png_get_image_height() returned %d", image_info->height); bit_depth = png_get_bit_depth(image_info->decoder_data.png_info.png_ptr, image_info->decoder_data.png_info.info_ptr); image_info->wprint_ifc->debug(DBG_VERBOSE, "_png_get_hdr(): png_get_bit_depth() returned %d", bit_depth); pixel_depth = image_info->decoder_data.png_info.info_ptr->pixel_depth; if ( (bit_depth == BITS_PER_CHANNEL) && (pixel_depth == BITS_PER_PIXEL) ) { image_info->num_components = pixel_depth/bit_depth; image_info->wprint_ifc->debug(DBG_LOG, "_png_get_hdr(): PNG %d x %d (%d components)", image_info->width, image_info->height, image_info->num_components); return(OK); } else { image_info->wprint_ifc->debug(DBG_ERROR, "_png_get_hdr(): ERROR: PNG format not supported. pix = %d, bit = %d", pixel_depth, bit_depth); return(ERROR); } } /* static wprint_png_get_hdr */
bool Image::load (const std::string &s) { // // The following is based on the libpng manual. http://www.libpng.org/pub/png/libpng-1.2.5-manual.html#section-3.1 // // // Check the file header // // Open the file std::ifstream infile; infile.open(s.c_str(), std::ifstream::in | std::ifstream::binary); // Read the header const unsigned int NUM_HEADER_BYTES_TO_READ = 8; char header[NUM_HEADER_BYTES_TO_READ]; infile.read(header, NUM_HEADER_BYTES_TO_READ); if (png_sig_cmp((png_bytep) header, 0, NUM_HEADER_BYTES_TO_READ)) { return false; } // // Read the image data // png_bytep *row_pointers = NULL; // 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_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { return false; } // Allocate/initialize the memory for image information 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); return false; } // 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))) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); delete row_pointers; // Gets allocated after here, but don't forget the jump! return false; } // Set custom read routine png_set_read_fn(png_ptr, &infile, &png_read_data); // If we have already read some of the signature png_set_sig_bytes(png_ptr, NUM_HEADER_BYTES_TO_READ); // // Read the entire image // // Read PNG header info png_read_info(png_ptr, info_ptr); int bit_depth, color_type, interlace_type; // Header info png_uint_32 width,height; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); // Strip 16 bit down to 8 bit png_set_strip_16(png_ptr); // Extract components to even bytes png_set_packing(png_ptr); // Expand grayscale images to 8 bit png_set_expand(png_ptr); // Add a filler byte when missing png_set_filler(png_ptr,0xFFFFFFFF,PNG_FILLER_AFTER); // Expand grayscale images to rgb png_set_gray_to_rgb(png_ptr); // Update the transformation info within libpng png_read_update_info(png_ptr, info_ptr); // Header info again png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); // Allocate target image allocate(width, height); // Handle Gamma png_set_gamma(png_ptr, 0.0, 0.0); // Setup row pointers row_pointers = new png_bytep[_data_height]; if (!row_pointers) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return false; } for (unsigned int y = 0; y < _data_height; ++y) { row_pointers[y] = reinterpret_cast<png_byte*>( &getPixel(0,y) ); } // Read the entire image png_read_image(png_ptr, row_pointers); // // Clean up // delete row_pointers; png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return true; }
/* 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 bit_depth, color_type, interlace_type, compression_type, filter_type, row_bytes; unsigned char signature[8]; png_structp volatile png_ptr = NULL; png_infop volatile info_ptr = NULL; unsigned long Width, Height; unsigned char *bits; unsigned char** volatile rows = NULL; BMGError tmp; /* error handler */ error = setjmp( err_jmp ); if ( error != 0 ) { 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 ); 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 ); /* bamboozle the PNG longjmp buffer */ /*generic PNG error handler*/ error = setjmp( png_jmpbuf( png_ptr ) ); if ( error > 0 ) longjmp( err_jmp, error ); /* attach file buffer to the png read pointer */ png_init_io( png_ptr, file ); /*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, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type ); img->width = (unsigned int) Width; img->height = (unsigned int) Height; img->bits_per_pixel = (unsigned char)32; img->scan_width = Width * 4; /* strip if color channel is larger than 8 bits */ if (bit_depth > 8) { png_set_strip_16(png_ptr); bit_depth = 8; } /* 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 (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); color_type = PNG_COLOR_TYPE_RGB; } /* expand 1,2,4 bit gray scale to 8 bit gray scale */ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); /* convert gray scale or gray scale + alpha to rgb color */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); color_type = 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); color_type = PNG_COLOR_TYPE_RGB_ALPHA; } /* convert rgb to rgba */ if (color_type == PNG_COLOR_TYPE_RGB) { png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); color_type = PNG_COLOR_TYPE_RGB_ALPHA; } /* punt invalid formats */ if (color_type != PNG_COLOR_TYPE_RGB_ALPHA) { longjmp(err_jmp, (int)errIncorrectFormat); } /* convert rgba to bgra */ png_set_bgr(png_ptr); img->palette_size = (unsigned short)0; img->bytes_per_palette_entry = 4U; tmp = AllocateBMGImage( img ); if ( tmp != BMG_OK ) longjmp( err_jmp, (int)tmp ); /* Update info structure */ 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 ); row_bytes = png_get_rowbytes(png_ptr, info_ptr); rows[0] = (unsigned char *)malloc( Height*row_bytes*sizeof(char)); if ( !rows[0] ) longjmp( err_jmp, (int)errMemoryAllocation ); for (int i = 1; i < (int)Height; i++ ) rows[i] = rows[i - 1] + row_bytes; /* read the entire image into rows */ png_read_image( png_ptr, rows ); bits = img->bits + (Height - 1) * img->scan_width; for (int 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, NULL); fclose( file ); return BMG_OK; }
BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file, 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_LIBPNG_VER_STRING, 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 < (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 < height; row++) { for (col = 0; col < 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 */
MMBitmapRef newMMBitmapFromPNG(const char *path, MMPNGReadError *err) { FILE *fp; uint8_t header[8]; png_struct *png_ptr = NULL; png_info *info_ptr = NULL; png_byte bit_depth, color_type; uint8_t *row, *bitmapData; uint8_t bytesPerPixel; png_uint_32 width, height, y; uint32_t bytewidth; if ((fp = fopen(path, "rb")) == NULL) { if (err != NULL) *err = kPNGAccessError; return NULL; } /* Initialize error code to generic value. */ if (err != NULL) *err = kPNGGenericError; /* Validate the PNG. */ if (fread(header, 1, sizeof header, fp) == 0) { if (err != NULL) *err = kPNGReadError; goto bail; } else if (!png_check_sig(header, sizeof(header))) { if (err != NULL) *err = kPNGInvalidHeaderError; goto bail; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) goto bail; info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) goto bail; /* Set up error handling. */ if (setjmp(png_jmpbuf(png_ptr))) { goto bail; } png_init_io(png_ptr, fp); /* Skip past the header. */ png_set_sig_bytes(png_ptr, sizeof header); png_read_info(png_ptr, info_ptr); /* Convert different image types to common type to be read. */ bit_depth = png_get_bit_depth(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); /* Convert color palettes to RGB. */ if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } /* Convert PNG to bit depth of 8. */ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { #ifdef PNG_LIBPNG_VER_SONUM #if PNG_LIBPNG_VER_SONUM >= 14 png_set_expand_gray_1_2_4_to_8(png_ptr); #else png_set_gray_1_2_4_to_8(png_ptr); #endif #else png_set_gray_1_2_4_to_8(png_ptr); #endif } else if (bit_depth == 16) { png_set_strip_16(png_ptr); } /* Convert transparency chunk to alpha channel. */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); } /* Convert gray images to RGB. */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); } /* Ignore alpha for now. */ if (color_type & PNG_COLOR_MASK_ALPHA) { png_set_strip_alpha(png_ptr); } /* Get image attributes. */ width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); bytesPerPixel = 3; /* All images decompress to this size. */ bytewidth = ADD_PADDING(width * bytesPerPixel); /* Align width. */ /* Decompress the PNG row by row. */ bitmapData = calloc(1, bytewidth * height); row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); if (bitmapData == NULL || row == NULL) goto bail; for (y = 0; y < height; ++y) { png_uint_32 x; const uint32_t rowOffset = y * bytewidth; uint8_t *rowptr = row; png_read_row(png_ptr, (png_byte *)row, NULL); for (x = 0; x < width; ++x) { const uint32_t colOffset = x * bytesPerPixel; MMRGBColor *color = (MMRGBColor *)(bitmapData + rowOffset + colOffset); color->red = *rowptr++; color->green = *rowptr++; color->blue = *rowptr++; } } free(row); /* Finish reading. */ png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return createMMBitmap(bitmapData, width, height, bytewidth, bytesPerPixel * 8, bytesPerPixel); bail: png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return NULL; }
bool Image::CreateImage(const char* pszImageFile) { StreamReader* pTextureStream = IFileUtil::GetInstance().LoadFile(pszImageFile); if (!pTextureStream || !pTextureStream->IsOK()) { SAFE_RELEASE(pTextureStream); return false; } png_structp pPngStruct = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!pPngStruct) { png_destroy_read_struct(&pPngStruct, NULL, NULL); // logout LOGE("load image file failed: %s", pszImageFile); SAFE_DELETE(pTextureStream); return false; } png_infop pPngInfo = png_create_info_struct(pPngStruct); if (!pPngInfo) { png_destroy_read_struct(&pPngStruct, &pPngInfo, NULL); // logout LOGE("create png info failed: %s", pszImageFile); SAFE_DELETE(pTextureStream); return false; } setjmp(png_jmpbuf(pPngStruct)); // define our own callback function for I/O instead of reading from a file png_set_read_fn(pPngStruct, pTextureStream, PngReaderCallback); png_read_info(pPngStruct, pPngInfo); m_nImageWidth = png_get_image_width(pPngStruct, pPngInfo); m_nImageHeight = png_get_image_height(pPngStruct, pPngInfo); // can be PNG_COLOR_TYPE_RGB, PNG_COLOR_TYPE_PALETTE, ... png_byte nColorType = png_get_color_type(pPngStruct, pPngInfo); m_nBPP = png_get_bit_depth(pPngStruct, pPngInfo); // convert stuff to appropriate formats! if(nColorType == PNG_COLOR_TYPE_PALETTE) { png_set_packing(pPngStruct); // expand data to 24-bit RGB or 32-bit RGBA if alpha available png_set_palette_to_rgb(pPngStruct); } // expand data to 24-bit RGB or 32-bit RGBA if alpha available if (nColorType == PNG_COLOR_TYPE_GRAY && m_nBPP < 8) png_set_expand_gray_1_2_4_to_8(pPngStruct); if (nColorType == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(pPngStruct); if (m_nBPP == 16) png_set_strip_16(pPngStruct); // expand paletted or RGB images with transparency to full alpha channels so the data will be available as RGBA quartets. if(png_get_valid(pPngStruct, pPngInfo, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(pPngStruct); // read image data into pRowPointers uchar** pRowPointers = new uchar*[m_nImageHeight]; for (int y = 0; y < m_nImageHeight; y++) { pRowPointers[y] = new uchar[m_nImageWidth * 4]; //each pixel(RGBA) has 4 bytes } png_read_image(pPngStruct, pRowPointers); // free the stream object and png structure png_destroy_read_struct(&pPngStruct, &pPngInfo, NULL); SAFE_RELEASE(pTextureStream); // store image data into our pRGBAData, each pixel(RGBA) has 4 bytes m_pPixelData = new uchar[m_nImageWidth * m_nImageHeight * 4]; //unlike store the pixel data from top-left corner, store them from bottom-left corner for OGLES Texture drawing... int nCurrPos = (m_nImageWidth * m_nImageHeight * 4) - (4 * m_nImageWidth); for(int row = 0; row < m_nImageHeight; row++) { for(int col = 0; col < (4 * m_nImageWidth); col += 4) { m_pPixelData[nCurrPos++] = pRowPointers[row][col + 0]; // red m_pPixelData[nCurrPos++] = pRowPointers[row][col + 1]; // green m_pPixelData[nCurrPos++] = pRowPointers[row][col + 2]; // blue m_pPixelData[nCurrPos++] = pRowPointers[row][col + 3]; // alpha } nCurrPos = (nCurrPos - (m_nImageWidth * 4) * 2); //move the pointer back two rows } // free pRowPointers for (int y = 0; y < m_nImageHeight; y++) { SAFE_DELETE_ARRAY(pRowPointers[y]); } SAFE_DELETE_ARRAY(pRowPointers); return true; }
bool loadSpriteFromPNG (const char * file, struct spriteBank *sprites, int index) { if (sprites->type<2) { char * error = joinStrings(file, "\n\nPNG files currently not supported in palette mode. Change to 32-bit mode and try again."); errorBox ("Can't open PNG file", error); delete error; return false; } // Open the file FILE * fp = fopen (file, "rb"); if (fp == NULL) { char * error = joinStrings(file, "\n\nThe file can't be opened. I don't know why."); errorBox ("Can't open PNG file", error); delete error; return false; } char tmp[10]; size_t bytes_read = fread(tmp, 1, 8, fp); if (bytes_read != 8 && ferror (fp)) { fprintf(stderr, "Reading error in loadSpriteFromPNG.\n"); } if (png_sig_cmp((png_byte *) tmp, 0, 8)) { fclose (fp); char * error = joinStrings(file, "\n\nIt doesn't appear to be a valid PNG image."); errorBox ("Can't open PNG file", error); delete error; return false; } png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fclose (fp); char * error = joinStrings(file, "\n\nError reading the file."); errorBox ("Can't open PNG file", error); delete error; return false; } 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); fclose (fp); char * error = joinStrings(file, "\n\nError reading the file."); errorBox ("Can't open PNG file", error); delete error; return false; } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose (fp); char * error = joinStrings(file, "\n\nError readin the file"); return errorBox ("Can't open PNG file", error); } png_init_io(png_ptr, fp); // Tell libpng which file to read png_set_sig_bytes(png_ptr, 8); // 8 bytes already read png_read_info(png_ptr, info_ptr); png_uint_32 width, height; int bit_depth, color_type, interlace_type, compression_type, filter_method; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_method); if (bit_depth < 8) png_set_packing(png_ptr); png_set_expand(png_ptr); 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) png_set_strip_16(png_ptr); png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER); png_read_update_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_method); int rowbytes = png_get_rowbytes(png_ptr, info_ptr); unsigned char * row_pointers[height]; unsigned char * data = new unsigned char [rowbytes*height]; for (int i = 0; i<height; i++) row_pointers[i] = data + i*rowbytes; png_read_image(png_ptr, (png_byte **) row_pointers); png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose (fp); if (sprites->sprites[index].data) delete sprites->sprites[index].data; sprites->sprites[index].data = data; sprites->sprites[index].width = width; sprites->sprites[index].height = height; int n, r, g, b; for (int x=0; x<width;x++) { for (int y=0; y<height; y++) { if (! sprites->sprites[index].data[4*width*y + x*4 + 3]) { n = r = g = b = 0; if (x>0 && sprites->sprites[index].data[4*width*y + (x-1)*4 + 3]) { n++; r+= sprites->sprites[index].data[4*width*y + (x-1)*4]; g+= sprites->sprites[index].data[4*width*y + (x-1)*4+1]; b+= sprites->sprites[index].data[4*width*y + (x-1)*4+2]; } if (x<width-1 && sprites->sprites[index].data[4*width*y + (x+1)*4 + 3]) { n++; r+= sprites->sprites[index].data[4*width*y + (x+1)*4]; g+= sprites->sprites[index].data[4*width*y + (x+1)*4+1]; b+= sprites->sprites[index].data[4*width*y + (x+1)*4+2]; } if (y>0 && sprites->sprites[index].data[4*width*(y-1) + x*4 + 3]) { n++; r+= sprites->sprites[index].data[4*width*(y-1) + x*4]; g+= sprites->sprites[index].data[4*width*(y-1) + x*4+1]; b+= sprites->sprites[index].data[4*width*(y-1) + x*4+2]; } if (y<height-1 && sprites->sprites[index].data[4*width*(y+1) + x*4 + 3]) { n++; r+= sprites->sprites[index].data[4*width*(y+1) + x*4]; g+= sprites->sprites[index].data[4*width*(y+1) + x*4+1]; b+= sprites->sprites[index].data[4*width*(y+1) + x*4+2]; } if (n) { r /= n; g /= n; b /= n; sprites->sprites[index].data[4*width*y + x*4]=r; sprites->sprites[index].data[4*width*y + x*4+1]=g; sprites->sprites[index].data[4*width*y + x*4+2]=b; } } } } loadSpriteTexture (sprites, index); return true; }
int fh_png_load(const char *name,unsigned char *buffer,int x,int y) { static const png_color_16 my_background = {0, 0, 0, 0, 0}; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; unsigned int i; int bit_depth, color_type, interlace_type; int number_passes,pass; png_byte * fbptr; FILE * fh; if(!(fh=fopen(name,"rb"))) return(FH_ERROR_FILE); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); if(png_ptr == NULL) { fclose(fh); return(FH_ERROR_FORMAT); } info_ptr = png_create_info_struct(png_ptr); if(info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); fclose(fh); return(FH_ERROR_FORMAT); } #if (PNG_LIBPNG_VER < 10500) if(setjmp(png_ptr->jmpbuf)) #else if(setjmp(png_jmpbuf(png_ptr))) #endif { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fh); return(FH_ERROR_FORMAT); } png_init_io(png_ptr,fh); 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_palette_to_rgb(png_ptr); png_set_background(png_ptr, (png_color_16*)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); /* other possibility for png_set_background: use png_get_bKGD */ } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); png_set_background(png_ptr, (png_color_16*)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); } if (color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); /* on Intel PC ?: if (bit_depth == 16) png_set_swap(png_ptr); */ number_passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr,info_ptr); if (width * 3 != png_get_rowbytes(png_ptr, info_ptr)) { printf("[png.cpp]: Error processing %s - please report (including image).\n", name); return(FH_ERROR_FORMAT); } for(pass = 0; pass < number_passes; pass++) { fbptr = (png_byte *)buffer; for (i = 0; i < height; i++, fbptr += width * 3) { png_read_row(png_ptr, fbptr, NULL); } } png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fh); return(FH_ERROR_OK); }
/** Configure the decoder so that decoded pixels are compatible with a FREE_IMAGE_TYPE format. Set conversion instructions as needed. @param png_ptr PNG handle @param info_ptr PNG info handle @param flags Decoder flags @param output_image_type Returned FreeImage converted image type @return Returns TRUE if successful, returns FALSE otherwise @see png_read_update_info */ static BOOL ConfigureDecoder(png_structp png_ptr, png_infop info_ptr, int flags, FREE_IMAGE_TYPE *output_image_type) { // get original image info const int color_type = png_get_color_type(png_ptr, info_ptr); const int bit_depth = png_get_bit_depth(png_ptr, info_ptr); const int pixel_depth = bit_depth * png_get_channels(png_ptr, info_ptr); FREE_IMAGE_TYPE image_type = FIT_BITMAP; // assume standard image type // check for transparency table or single transparent color BOOL bIsTransparent = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) == PNG_INFO_tRNS ? TRUE : FALSE; // check allowed combinations of colour type and bit depth // then get converted FreeImage type switch(color_type) { case PNG_COLOR_TYPE_GRAY: // color type '0', bitdepth = 1, 2, 4, 8, 16 switch(bit_depth) { case 1: case 2: case 4: case 8: // expand grayscale images to the full 8-bit from 2-bit/pixel if (pixel_depth == 2) { png_set_expand_gray_1_2_4_to_8(png_ptr); } // if a tRNS chunk is provided, we must also expand the grayscale data to 8-bits, // this allows us to make use of the transparency table with existing FreeImage methods if (bIsTransparent && (pixel_depth < 8)) { png_set_expand_gray_1_2_4_to_8(png_ptr); } break; case 16: image_type = (pixel_depth == 16) ? FIT_UINT16 : FIT_UNKNOWN; // 16-bit grayscale images can contain a transparent value (shade) // if found, expand the transparent value to a full alpha channel if (bIsTransparent && (image_type != FIT_UNKNOWN)) { // expand tRNS to a full alpha channel png_set_tRNS_to_alpha(png_ptr); // expand new 16-bit gray + 16-bit alpha to full 64-bit RGBA png_set_gray_to_rgb(png_ptr); image_type = FIT_RGBA16; } break; default: image_type = FIT_UNKNOWN; break; } break; case PNG_COLOR_TYPE_RGB: // color type '2', bitdepth = 8, 16 switch(bit_depth) { case 8: image_type = (pixel_depth == 24) ? FIT_BITMAP : FIT_UNKNOWN; break; case 16: image_type = (pixel_depth == 48) ? FIT_RGB16 : FIT_UNKNOWN; break; default: image_type = FIT_UNKNOWN; break; } // sometimes, 24- or 48-bit images may contain transparency information // check for this use case and convert to an alpha-compatible format if (bIsTransparent && (image_type != FIT_UNKNOWN)) { // if the image is 24-bit RGB, mark it as 32-bit; if it is 48-bit, mark it as 64-bit image_type = (pixel_depth == 24) ? FIT_BITMAP : (pixel_depth == 48) ? FIT_RGBA16 : FIT_UNKNOWN; // expand tRNS chunk to alpha channel png_set_tRNS_to_alpha(png_ptr); } break; case PNG_COLOR_TYPE_PALETTE: // color type '3', bitdepth = 1, 2, 4, 8 switch(bit_depth) { case 1: case 2: case 4: case 8: // expand palette images to the full 8 bits from 2 bits/pixel if (pixel_depth == 2) { png_set_packing(png_ptr); } // if a tRNS chunk is provided, we must also expand the palletized data to 8-bits, // this allows us to make use of the transparency table with existing FreeImage methods if (bIsTransparent && (pixel_depth < 8)) { png_set_packing(png_ptr); } break; default: image_type = FIT_UNKNOWN; break; } break; case PNG_COLOR_TYPE_GRAY_ALPHA: // color type '4', bitdepth = 8, 16 switch(bit_depth) { case 8: // 8-bit grayscale + 8-bit alpha => convert to 32-bit RGBA image_type = (pixel_depth == 16) ? FIT_BITMAP : FIT_UNKNOWN; break; case 16: // 16-bit grayscale + 16-bit alpha => convert to 64-bit RGBA image_type = (pixel_depth == 32) ? FIT_RGBA16 : FIT_UNKNOWN; break; default: image_type = FIT_UNKNOWN; break; } // expand 8-bit greyscale + 8-bit alpha to 32-bit // expand 16-bit greyscale + 16-bit alpha to 64-bit png_set_gray_to_rgb(png_ptr); break; case PNG_COLOR_TYPE_RGB_ALPHA: // color type '6', bitdepth = 8, 16 switch(bit_depth) { case 8: break; case 16: image_type = (pixel_depth == 64) ? FIT_RGBA16 : FIT_UNKNOWN; break; default: image_type = FIT_UNKNOWN; break; } break; } // check for unknown or invalid formats if(image_type == FIT_UNKNOWN) { *output_image_type = image_type; return FALSE; } #ifndef FREEIMAGE_BIGENDIAN if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) { // turn on 16-bit byte swapping png_set_swap(png_ptr); } #endif #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR if((image_type == FIT_BITMAP) && ((color_type == PNG_COLOR_TYPE_RGB) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA))) { // flip the RGB pixels to BGR (or RGBA to BGRA) png_set_bgr(png_ptr); } #endif // gamma correction // 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_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) { double gamma = 0; double screen_gamma = 2.2; if (png_get_gAMA(png_ptr, info_ptr, &gamma) && ( flags & PNG_IGNOREGAMMA ) != PNG_IGNOREGAMMA) { png_set_gamma(png_ptr, screen_gamma, gamma); } } // all transformations have been registered; now update info_ptr data png_read_update_info(png_ptr, info_ptr); // return the output image type *output_image_type = image_type; return TRUE; }
static unsigned char* png_file_load (const char *file, int *width, int *height) { FILE *fd; unsigned char *data; unsigned char header[8]; int bit_depth, color_type; png_uint_32 png_width, png_height, i, rowbytes; png_structp png_ptr; png_infop info_ptr; png_bytep *row_pointers; if ((fd = fopen( file, "rb" )) == NULL) return NULL; fread( header, 1, 8, fd ); if ( ! png_check_sig( header, 8 ) ) { fclose(fd); return NULL; } png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if ( ! png_ptr ) { fclose(fd); return NULL; } info_ptr = png_create_info_struct(png_ptr); if ( ! info_ptr ) { png_destroy_read_struct( &png_ptr, (png_infopp)NULL, (png_infopp)NULL); fclose(fd); return NULL; } if (setjmp (png_jmpbuf (png_ptr))) { png_destroy_read_struct( &png_ptr, &info_ptr, NULL); fclose(fd); return NULL; } png_init_io( png_ptr, fd ); png_set_sig_bytes( png_ptr, 8); png_read_info( png_ptr, info_ptr); png_get_IHDR( png_ptr, info_ptr, &png_width, &png_height, &bit_depth, &color_type, NULL, NULL, NULL); *width = (int) png_width; *height = (int) png_height; if ( bit_depth == 16 ) png_set_strip_16(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); if (( color_type == PNG_COLOR_TYPE_GRAY ) || ( color_type == PNG_COLOR_TYPE_GRAY_ALPHA )) png_set_gray_to_rgb(png_ptr); /* Add alpha */ if (( color_type == PNG_COLOR_TYPE_GRAY ) || ( color_type == PNG_COLOR_TYPE_RGB )) png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER); /* req 1.2.7 */ if (( color_type == PNG_COLOR_TYPE_PALETTE )|| ( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ))) png_set_expand(png_ptr); png_read_update_info( png_ptr, info_ptr); /* allocate space for data and row pointers */ rowbytes = png_get_rowbytes( png_ptr, info_ptr); data = (unsigned char *) malloc( (rowbytes*(*height + 1))); row_pointers = (png_bytep *) malloc( (*height)*sizeof(png_bytep)); if (( data == NULL )||( row_pointers == NULL )) { png_destroy_read_struct( &png_ptr, &info_ptr, NULL); free(data); free(row_pointers); return NULL; } for ( i = 0; i < *height; i++ ) row_pointers[i] = data + i*rowbytes; png_read_image( png_ptr, row_pointers ); png_read_end( png_ptr, NULL); free(row_pointers); png_destroy_read_struct( &png_ptr, &info_ptr, NULL); fclose(fd); return data; }
int fh_png_load(char *name,unsigned char *buffer, unsigned char ** alpha,int x,int y) { png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int i; int bit_depth, color_type, interlace_type; int number_passes,pass, trans = 0; char *rp; png_bytep rptr[2]; char *fbptr; FILE *fh; if(!(fh=fopen(name,"rb"))) return(FH_ERROR_FILE); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); if (png_ptr == NULL) return(FH_ERROR_FORMAT); info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); fclose(fh); return(FH_ERROR_FORMAT); } rp=0; if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); if(rp) free(rp); fclose(fh); return(FH_ERROR_FORMAT); } png_init_io(png_ptr,fh); 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); if (bit_depth < 8) png_set_packing(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type== PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { trans = 1; png_set_tRNS_to_alpha(png_ptr); } if(bit_depth == 16) png_set_strip_16(png_ptr); number_passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr,info_ptr); if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGB_ALPHA || trans) { unsigned char * alpha_buffer = (unsigned char*) malloc(width * height); unsigned char * aptr; rp = (char*) malloc(width * 4); rptr[0] = (png_bytep) rp; *alpha = alpha_buffer; for (pass = 0; pass < number_passes; pass++) { fbptr = buffer; aptr = alpha_buffer; for(i=0; i<height; i++) { int n; unsigned char *trp = rp; png_read_rows(png_ptr, rptr, NULL, 1); for(n = 0; n < width; n++, fbptr += 3, trp += 4) { memcpy(fbptr, trp, 3); *(aptr++) = trp[3]; } } } free(rp); } else { for (pass = 0; pass < number_passes; pass++) { fbptr = buffer; for(i=0; i<height; i++, fbptr += width*3) { rptr[0] = (png_bytep) fbptr; png_read_rows(png_ptr, rptr, NULL, 1); } } } png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fh); return(FH_ERROR_OK); }
void ImagePNG::ReadPNG(FILE* stream, const void* buffer, bool transparent, int& width, int& height, void*& pixels) { pixels = NULL; png_struct *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { Output::Error("Couldn't allocate PNG structure"); return; } png_info *info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { Output::Error("Couldn't allocate PNG info structure"); return; } if (stream != NULL) png_init_io(png_ptr, stream); else png_set_read_fn(png_ptr, (png_voidp) &buffer, read_data); png_read_info(png_ptr, info_ptr); png_uint_32 w, h; int bit_depth, color_type; png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, NULL, NULL, NULL); png_color black = {0,0,0}; png_colorp palette; int num_palette = 0; switch (color_type) { case PNG_COLOR_TYPE_PALETTE: if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); else if (transparent && png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); png_set_palette_to_rgb(png_ptr); png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); break; case PNG_COLOR_TYPE_GRAY: png_set_gray_to_rgb(png_ptr); if (bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); if (transparent) { palette = &black; num_palette = 1; } break; case PNG_COLOR_TYPE_GRAY_ALPHA: png_set_gray_to_rgb(png_ptr); if (bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); break; case PNG_COLOR_TYPE_RGB: png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); break; case PNG_COLOR_TYPE_RGB_ALPHA: break; } if (bit_depth < 8) png_set_packing(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); png_read_update_info(png_ptr, info_ptr); width = w; height = h; pixels = malloc(w * h * 4); for (png_uint_32 y = 0; y < h; y++) { png_bytep dst = (png_bytep) pixels + y * w * 4; png_read_row(png_ptr, dst, NULL); } if (transparent && num_palette > 0) { png_color& ck = palette[0]; uint8 ck1[4] = {ck.red, ck.green, ck.blue, 255}; uint8 ck2[4] = {ck.red, ck.green, ck.blue, 0}; uint32 srckey = *(uint32*)ck1; uint32 dstkey = *(uint32*)ck2; uint32* p = (uint32*) pixels; for (unsigned i = 0; i < w * h; i++, p++) if (*p == srckey) *p = dstkey; } png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); }
void png_reader<T>::read(unsigned x0, unsigned y0,image_data_32& image) { stream_.clear(); stream_.seekg(0, std::ios_base::beg); png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,0,0,0); if (!png_ptr) { 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; png_struct_guard sguard(&png_ptr,&info_ptr); info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) throw image_reader_exception("failed to create info_ptr"); png_set_read_fn(png_ptr, (png_voidp)&stream_, 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 const std::unique_ptr<png_bytep[]> 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_ - x0); unsigned h=std::min(unsigned(image.height()),height_ - y0); unsigned rowbytes=png_get_rowbytes(png_ptr, info_ptr); const std::unique_ptr<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 < (y0 + h)) { image.setRow(i-y0,reinterpret_cast<unsigned*>(&row[x0 * 4]),w); } } //END } png_read_end(png_ptr,0); }
bool PngDecoder::readData( Mat& img ) { bool result = false; AutoBuffer<uchar*> _buffer(m_height); uchar** buffer = _buffer; int color = img.channels() > 1; uchar* data = img.data; int step = (int)img.step; if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height ) { png_structp png_ptr = (png_structp)m_png_ptr; png_infop info_ptr = (png_infop)m_info_ptr; png_infop end_info = (png_infop)m_end_info; if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 ) { int y; if( img.depth() == CV_8U && m_bit_depth == 16 ) png_set_strip_16( png_ptr ); else if( !isBigEndian() ) png_set_swap( png_ptr ); if(img.channels() < 4) { /* observation: png_read_image() writes 400 bytes beyond * end of data when reading a 400x118 color png * "mpplus_sand.png". OpenCV crashes even with demo * programs. Looking at the loaded image I'd say we get 4 * bytes per pixel instead of 3 bytes per pixel. Test * indicate that it is a good idea to always ask for * stripping alpha.. 18.11.2004 Axel Walthelm */ png_set_strip_alpha( png_ptr ); } if( m_color_type == PNG_COLOR_TYPE_PALETTE ) png_set_palette_to_rgb( png_ptr ); if( m_color_type == PNG_COLOR_TYPE_GRAY && m_bit_depth < 8 ) #if (PNG_LIBPNG_VER_MAJOR*10000 + PNG_LIBPNG_VER_MINOR*100 + PNG_LIBPNG_VER_RELEASE >= 10209) || \ (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR == 0 && PNG_LIBPNG_VER_RELEASE >= 18) png_set_expand_gray_1_2_4_to_8( png_ptr ); #else png_set_gray_1_2_4_to_8( png_ptr ); #endif if( CV_MAT_CN(m_type) > 1 && color ) png_set_bgr( png_ptr ); // convert RGB to BGR else if( color ) png_set_gray_to_rgb( png_ptr ); // Gray->RGB else png_set_rgb_to_gray( png_ptr, 1, 0.299, 0.587 ); // RGB->Gray png_read_update_info( png_ptr, info_ptr ); for( y = 0; y < m_height; y++ ) buffer[y] = data + y*step; png_read_image( png_ptr, buffer ); png_read_end( png_ptr, end_info ); result = true; } } close(); return result; }
/** Our implementation of libPNG callbacks */ void haveInfo() { int bitDepth, colorType, interlaceType; png_get_IHDR(pngReadStruct, pngInfoStruct, &width, &height, &bitDepth, &colorType, &interlaceType, 0, 0); if (!ImageManager::isAcceptableSize(width, height)) { libPngError = true; return; } //Ask libPNG to change bit depths we don't support if (bitDepth < 8) #if PNG_LIBPNG_VER < 10400 png_set_gray_1_2_4_to_8(pngReadStruct); #else png_set_expand_gray_1_2_4_to_8(pngReadStruct); #endif if (bitDepth > 8) png_set_strip_16 (pngReadStruct); //Some images (basically, only paletted ones) may have alpha //included as part of a tRNS chunk. We want to convert that to regular alpha //channel.. bool haveTRNS = false; if (png_get_valid(pngReadStruct, pngInfoStruct, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(pngReadStruct); haveTRNS = true; if (colorType == PNG_COLOR_TYPE_RGB) colorType = PNG_COLOR_TYPE_RGB_ALPHA; //Paranoia.. else if (colorType == PNG_COLOR_TYPE_GRAY) colorType = PNG_COLOR_TYPE_GRAY_ALPHA; } ImageFormat imFrm; //Prepare for mapping from colorType to our format descriptors. switch (colorType) { case PNG_COLOR_TYPE_GRAY: imFrm.greyscaleSetup(); break; case PNG_COLOR_TYPE_GRAY_ALPHA: //We don't natively support 8-bit plus alpha, so ask libPNG to expand it out to RGB png_set_gray_to_rgb(pngReadStruct); imFrm.type = ImageFormat::Image_ARGB_32; break; case PNG_COLOR_TYPE_PALETTE: //For now, we handle paletted images as RGB or ARGB //### TODO: handle non-alpha paletted images with a sufficiently small palette as //paletted imFrm.type = haveTRNS ? ImageFormat::Image_ARGB_32 : ImageFormat::Image_RGB_32; png_set_palette_to_rgb(pngReadStruct); break; case PNG_COLOR_TYPE_RGB: imFrm.type = ImageFormat::Image_RGB_32; break; case PNG_COLOR_TYPE_RGB_ALPHA: imFrm.type = ImageFormat::Image_ARGB_32; break; default: //Huh? libPngError = true; return; } //Configure padding/byte swapping if need be (32-bit images) //We want a 32-bit value with ARGB. //This means that for little-endian, in memory we should have BGRA, //and for big-endian, well, ARGB if (imFrm.type == ImageFormat::Image_RGB_32) { //Need fillers, plus perhaps BGR swapping for non-alpha #if Q_BYTE_ORDER == Q_BIG_ENDIAN || defined(__BIG_ENDIAN__) png_set_filler(pngReadStruct, 0xff, PNG_FILLER_BEFORE); #else png_set_filler(pngReadStruct, 0xff, PNG_FILLER_AFTER); png_set_bgr (pngReadStruct); #endif } else if (imFrm.type == ImageFormat::Image_ARGB_32) { #if Q_BYTE_ORDER == Q_BIG_ENDIAN || defined(__BIG_ENDIAN__) png_set_swap_alpha(pngReadStruct); //ARGB, not RGBA #else png_set_bgr (pngReadStruct); //BGRA #endif } //Remember depth, for our own use depth = imFrm.depth(); //handle interlacing if (interlaceType != PNG_INTERLACE_NONE) { interlaced = true; scanlineBuf = new unsigned char[depth * width]; png_set_interlace_handling(pngReadStruct); // Give up on premultiply in this case.. if (imFrm.type == ImageFormat::Image_ARGB_32) imFrm.type = ImageFormat::Image_ARGB_32_DontPremult; } notifySingleFrameImage(width, height, imFrm); //OK, time to start input png_read_update_info(pngReadStruct, pngInfoStruct); }
SDL_Surface *TCOD_sys_read_png(const char *filename) { png_uint_32 png_width,png_height,y; int png_bit_depth,png_color_type,png_interlace_type; png_structp png_ptr; png_infop info_ptr; FILE *fp; SDL_Surface *bitmap; png_bytep *row_pointers; if ((fp = fopen(filename, "rb")) == NULL) return NULL; /* 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,NULL, NULL, NULL); if (png_ptr == NULL) { fclose(fp); return NULL; } /* Allocate/initialize the memory for image information. REQUIRED. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(fp); png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); return NULL; } /* Set error handling if you are using the setjmp/longjmp method (this is * the normal method of doing things with libpng). REQUIRED unless you * set up your own error handlers in the png_create_read_struct() earlier. */ if (setjmp(png_jmpbuf(png_ptr))) { /* Free all of the memory associated with the png_ptr and info_ptr */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); fclose(fp); /* If we get here, we had a problem reading the file */ return NULL; } png_init_io(png_ptr, fp); /* * 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 * dithering, 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_TRANSFORM_IDENTITY, png_voidp_NULL); */ /* get info about the image */ png_read_info(png_ptr,info_ptr); png_get_IHDR(png_ptr,info_ptr,&png_width,&png_height,&png_bit_depth,&png_color_type, &png_interlace_type,NULL,NULL); /* convert the image to a format suitable with libtcod */ png_set_strip_16(png_ptr); /* 16 bits channels => 8 bits channels */ png_set_packing(png_ptr); /* 1,2,4 bits depth => 24/32 bits depth */ if ( png_color_type == PNG_COLOR_TYPE_GRAY ) png_set_expand(png_ptr); /* grayscale => color */ if ( png_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) png_set_gray_to_rgb(png_ptr); /* update the image information */ png_read_update_info(png_ptr,info_ptr); png_get_IHDR(png_ptr,info_ptr,&png_width,&png_height,&png_bit_depth,&png_color_type, &png_interlace_type,NULL,NULL); /* create the SDL surface */ bitmap=TCOD_sys_get_surface(png_width,png_height,info_ptr->channels == 4); /* get row data */ row_pointers=(png_bytep *)malloc(sizeof(png_bytep)*png_height); for (y=0; y< png_height; y++ ) { row_pointers[y]=(png_bytep)(Uint8 *)(bitmap->pixels) + y * bitmap->pitch; } /* read png data directly into the SDL surface */ png_read_image(png_ptr,row_pointers); /* clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); free(row_pointers); /* close the file */ fclose(fp); return bitmap; }
PNGImage LoadImagePNG(const char *path) { PNGImage loadedImage; loadedImage.loadedSuccessfully = GL_FALSE; FILE *PNG_file = fopen(path, "rb"); if (PNG_file == NULL) { printf("Can't open PNG file %s\n", path); return loadedImage; } GLubyte PNG_header[PNG_HEADER_SIZE]; fread(PNG_header, 1, PNG_HEADER_SIZE, PNG_file); if (png_sig_cmp(PNG_header, 0, PNG_HEADER_SIZE) != 0) { printf("%s is not a PNG file\n", path); return loadedImage; } png_structp PNG_reader = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (PNG_reader == NULL) { printf("Can't start reading PNG file %s\n", path); fclose(PNG_file); return loadedImage; } png_infop PNG_info = png_create_info_struct(PNG_reader); if (PNG_info == NULL) { printf("Can't get info for PNG file %s\n", path); png_destroy_read_struct(&PNG_reader, NULL, NULL); fclose(PNG_file); return loadedImage; } png_infop PNG_end_info = png_create_info_struct(PNG_reader); if (PNG_end_info == NULL) { printf("Can't get end info for PNG file %s\n", path); png_destroy_read_struct(&PNG_reader, &PNG_info, NULL); fclose(PNG_file); return loadedImage; } if (setjmp(png_jmpbuf(PNG_reader))) { printf("Can't load PNG file %s\n", path); png_destroy_read_struct(&PNG_reader, &PNG_info, &PNG_end_info); fclose(PNG_file); return loadedImage; } png_init_io(PNG_reader, PNG_file); png_set_sig_bytes(PNG_reader, PNG_HEADER_SIZE); png_read_info(PNG_reader, PNG_info); // we have to do a custom transformation to premultiply the alpha of the image png_set_read_user_transform_fn(PNG_reader, png_read_premultiply_alpha); png_uint_32 width, height; int bit_depth, color_type; png_get_IHDR(PNG_reader, PNG_info, &width, &height, &bit_depth, &color_type,NULL, NULL, NULL); if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(PNG_reader); } if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(PNG_reader); } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(PNG_reader); } if (png_get_valid(PNG_reader, PNG_info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(PNG_reader); } else { png_set_filler(PNG_reader, 0xff, PNG_FILLER_AFTER); } if (bit_depth == 16) { png_set_strip_16(PNG_reader); } png_read_update_info(PNG_reader, PNG_info); png_uint_32 widthPow2, heightPow2; widthPow2 = pow2(width); heightPow2 = pow2(height); png_byte* PNG_image_buffer = (png_byte*)malloc(4 * widthPow2 * heightPow2); memset(PNG_image_buffer,0,4*widthPow2*heightPow2); // clear image buffer png_byte** PNG_rows = (png_byte**)malloc(height * sizeof(png_byte*)); png_uint_32 rowBytes = widthPow2*4; // load the image from the bottom up /* image texture in mem looks like: -------- | | |xxxx | |xxxx | -------- where 'x's represent actual image data and the lines are the image buffer. so the image is aligned at the (0,0) texel coordinate of the image buffer. */ unsigned int row; for (row = 0; row < height; ++row) { PNG_rows[height-1-row] = PNG_image_buffer + (row * rowBytes); } png_read_image(PNG_reader, PNG_rows); free(PNG_rows); png_destroy_read_struct(&PNG_reader, &PNG_info, &PNG_end_info); fclose(PNG_file); GLuint textureID = 0; glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, widthPow2, heightPow2, 0, GL_RGBA, GL_UNSIGNED_BYTE, PNG_image_buffer); free(PNG_image_buffer); loadedImage.width = width; loadedImage.height = height; loadedImage.widthPow2 = widthPow2; loadedImage.heightPow2 = heightPow2; loadedImage.textureId = textureID; loadedImage.loadedSuccessfully = GL_TRUE; return loadedImage; }
Py::Object _png_module::read_png(const Py::Tuple& args) { args.verify_length(1); png_byte header[8]; // 8 is the maximum size that can be checked FILE* fp = NULL; bool close_file = false; Py::Object py_fileobj = Py::Object(args[0]); #if PY_MAJOR_VERSION >= 3 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 PY_MAJOR_VERSION >= 3 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 = info_ptr->width; png_uint_32 height = info_ptr->height; int bit_depth = info_ptr->bit_depth; // 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 ((info_ptr->color_type != 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 (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } // If there's an alpha channel convert gray to RGB if (info_ptr->color_type == 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 (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) { dimensions[2] = 4; //RGBA images } else if (info_ptr->color_type & 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 = (info_ptr->color_type & PNG_COLOR_MASK_COLOR) ? 3 : 2; double max_value = (1 << ((bit_depth < 8) ? 8 : 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; } } } } //free the png memory png_read_end(png_ptr, info_ptr); #ifndef png_infopp_NULL png_destroy_read_struct(&png_ptr, &info_ptr, NULL); #else png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); #endif if (close_file) { fclose(fp); } for (row = 0; row < height; row++) { delete [] row_pointers[row]; } delete [] row_pointers; return Py::asObject((PyObject*)A); }
/**************************************************************************** * DecodeBlock: the whole thing **************************************************************************** * This function must be fed with a complete compressed frame. ****************************************************************************/ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block; picture_t *p_pic = 0; png_uint_32 i_width, i_height; int i_color_type, i_interlace_type, i_compression_type, i_filter_type; int i_bit_depth, i; png_structp p_png; png_infop p_info, p_end_info; png_bytep *p_row_pointers = NULL; if( !pp_block || !*pp_block ) return NULL; p_block = *pp_block; p_sys->b_error = false; if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY ) { block_Release( p_block ); *pp_block = NULL; return NULL; } p_png = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ); if( p_png == NULL ) { block_Release( p_block ); *pp_block = NULL; return NULL; } p_info = png_create_info_struct( p_png ); if( p_info == NULL ) { png_destroy_read_struct( &p_png, NULL, NULL ); block_Release( p_block ); *pp_block = NULL; return NULL; } p_end_info = png_create_info_struct( p_png ); if( p_end_info == NULL ) { png_destroy_read_struct( &p_png, &p_info, NULL ); block_Release( p_block ); *pp_block = NULL; return NULL; } /* libpng longjmp's there in case of error */ if( setjmp( png_jmpbuf( p_png ) ) ) goto error; png_set_read_fn( p_png, (void *)p_block, user_read ); png_set_error_fn( p_png, (void *)p_dec, user_error, user_warning ); png_read_info( p_png, p_info ); if( p_sys->b_error ) goto error; png_get_IHDR( p_png, p_info, &i_width, &i_height, &i_bit_depth, &i_color_type, &i_interlace_type, &i_compression_type, &i_filter_type); if( p_sys->b_error ) goto error; /* Set output properties */ p_dec->fmt_out.i_codec = VLC_CODEC_RGBA; p_dec->fmt_out.video.i_width = i_width; p_dec->fmt_out.video.i_height = i_height; p_dec->fmt_out.video.i_sar_num = 1; p_dec->fmt_out.video.i_sar_den = 1; p_dec->fmt_out.video.i_rmask = 0x000000ff; p_dec->fmt_out.video.i_gmask = 0x0000ff00; p_dec->fmt_out.video.i_bmask = 0x00ff0000; if( i_color_type == PNG_COLOR_TYPE_PALETTE ) png_set_palette_to_rgb( p_png ); if( i_color_type == PNG_COLOR_TYPE_GRAY || i_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) png_set_gray_to_rgb( p_png ); /* Strip to 8 bits per channel */ if( i_bit_depth == 16 ) png_set_strip_16( p_png ); if( png_get_valid( p_png, p_info, PNG_INFO_tRNS ) ) { png_set_tRNS_to_alpha( p_png ); } else if( !(i_color_type & PNG_COLOR_MASK_ALPHA) ) { p_dec->fmt_out.i_codec = VLC_CODEC_RGB24; } /* Get a new picture */ p_pic = decoder_NewPicture( p_dec ); if( !p_pic ) goto error; /* Decode picture */ p_row_pointers = malloc( sizeof(png_bytep) * i_height ); if( !p_row_pointers ) goto error; for( i = 0; i < (int)i_height; i++ ) p_row_pointers[i] = p_pic->p->p_pixels + p_pic->p->i_pitch * i; png_read_image( p_png, p_row_pointers ); if( p_sys->b_error ) goto error; png_read_end( p_png, p_end_info ); if( p_sys->b_error ) goto error; png_destroy_read_struct( &p_png, &p_info, &p_end_info ); free( p_row_pointers ); p_pic->date = p_block->i_pts > VLC_TS_INVALID ? p_block->i_pts : p_block->i_dts; block_Release( p_block ); *pp_block = NULL; return p_pic; error: free( p_row_pointers ); png_destroy_read_struct( &p_png, &p_info, &p_end_info ); block_Release( p_block ); *pp_block = NULL; return NULL; }
static gboolean setup_png_transformations(png_structp png_read_ptr, png_infop png_info_ptr, GError **error, png_uint_32* width_p, png_uint_32* height_p, int* color_type_p) { png_uint_32 width, height; int bit_depth, color_type, interlace_type, compression_type, filter_type; int channels; /* Get the image info */ /* Must check bit depth, since png_get_IHDR generates an FPE on bit_depth 0. */ bit_depth = png_get_bit_depth (png_read_ptr, png_info_ptr); if (bit_depth < 1 || bit_depth > 16) { g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Bits per channel of PNG image is invalid.")); return FALSE; } png_get_IHDR (png_read_ptr, png_info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type); /* set_expand() basically needs to be called unless we are already in RGB/RGBA mode */ if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8) { /* Convert indexed images to RGB */ png_set_expand (png_read_ptr); } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { /* Convert grayscale to RGB */ png_set_expand (png_read_ptr); } else if (png_get_valid (png_read_ptr, png_info_ptr, PNG_INFO_tRNS)) { /* If we have transparency header, convert it to alpha channel */ png_set_expand(png_read_ptr); } else if (bit_depth < 8) { /* If we have < 8 scale it up to 8 */ png_set_expand(png_read_ptr); /* Conceivably, png_set_packing() is a better idea; * God only knows how libpng works */ } /* If we are 16-bit, convert to 8-bit */ if (bit_depth == 16) { png_set_strip_16(png_read_ptr); } /* If gray scale, convert to RGB */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_read_ptr); } /* If interlaced, handle that */ if (interlace_type != PNG_INTERLACE_NONE) { png_set_interlace_handling(png_read_ptr); } /* Update the info the reflect our transformations */ png_read_update_info(png_read_ptr, png_info_ptr); png_get_IHDR (png_read_ptr, png_info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type); *width_p = width; *height_p = height; *color_type_p = color_type; /* Check that the new info is what we want */ if (width == 0 || height == 0) { g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Transformed PNG has zero width or height.")); return FALSE; } if (bit_depth != 8) { g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Bits per channel of transformed PNG is not 8.")); return FALSE; } if ( ! (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) ) { g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Transformed PNG not RGB or RGBA.")); return FALSE; } channels = png_get_channels(png_read_ptr, png_info_ptr); if ( ! (channels == 3 || channels == 4) ) { g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Transformed PNG has unsupported number of channels, must be 3 or 4.")); return FALSE; } return TRUE; }