FloatPixMapRef FPMCreateWithPNGCustom(png_voidp ioPtr, png_rw_ptr readDataFn, FPMGammaFactor desiredGamma, FPMPNGErrorHandler errorHandler) { png_structp png = NULL; png_infop pngInfo = NULL; png_infop pngEndInfo = NULL; FloatPixMapRef result = NULL; png_uint_32 i, width, height, rowBytes; int depth, colorType; png_bytepp rows = NULL; void *data = NULL; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, errorHandler, PNGError, PNGWarning); if (png == NULL) goto FAIL; pngInfo = png_create_info_struct(png); if (pngInfo == NULL) goto FAIL; pngEndInfo = png_create_info_struct(png); if (pngEndInfo == NULL) goto FAIL; if (setjmp(png_jmpbuf(png))) { // libpng will jump here on error. goto FAIL; } png_set_read_fn(png, ioPtr, readDataFn); png_read_info(png, pngInfo); if (!png_get_IHDR(png, pngInfo, &width, &height, &depth, &colorType, NULL, NULL, NULL)) goto FAIL; #if __LITTLE_ENDIAN__ if (depth == 16) png_set_swap(png); #endif if (depth <= 8 && !(colorType & PNG_COLOR_MASK_ALPHA)) { png_set_filler(png, 0xFF, PNG_FILLER_AFTER); } png_set_gray_to_rgb(png); if (depth < 8) { png_set_packing(png); png_set_expand(png); } png_read_update_info(png, pngInfo); rowBytes = png_get_rowbytes(png, pngInfo); rows = malloc(sizeof *rows * height); data = malloc(rowBytes * height); if (rows == NULL || data == NULL) goto FAIL; // Set up row pointers. for (i = 0; i < height; i++) { rows[i] = (png_bytep)data + i * rowBytes; } png_read_image(png, rows); png_read_end(png, pngEndInfo); free(rows); result = ConvertPNGData(data, width, height, rowBytes, pngInfo->bit_depth, pngInfo->color_type); if (result != NULL) { double invGamma = 1.0/kFPMGammaSRGB; png_get_gAMA(png, pngInfo, &invGamma); FPMApplyGamma(result, 1.0/invGamma, desiredGamma, pngInfo->bit_depth == 16 ? 65536 : 256); } png_destroy_read_struct(&png, &pngInfo, &pngEndInfo); free(data); return result; FAIL: FPMRelease(&result); if (png != NULL) png_destroy_read_struct(&png, &pngInfo, &pngEndInfo); free(rows); free(data); return NULL; }
PSD GdDecodePNG(buffer_t * src) { unsigned char hdr[8], **rows; png_structp state; png_infop pnginfo; png_uint_32 width, height; int bit_depth, color_type, i; double file_gamma; int channels, data_format; PSD pmd; GdImageBufferSeekTo(src, 0UL); if(GdImageBufferRead(src, hdr, 8) != 8) return NULL; if(png_sig_cmp(hdr, 0, 8)) return NULL; if(!(state = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) goto nomem; if(!(pnginfo = png_create_info_struct(state))) { png_destroy_read_struct(&state, NULL, NULL); goto nomem; } if(setjmp(png_jmpbuf(state))) { png_destroy_read_struct(&state, &pnginfo, NULL); return NULL; } /* Set up the input function */ png_set_read_fn(state, src, png_read_buffer); /* png_init_io(state, src); */ png_set_sig_bytes(state, 8); png_read_info(state, pnginfo); png_get_IHDR(state, pnginfo, &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 (state); /* expand images to bit-depth 8 (only applicable for grayscale images) */ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand (state); /* transform transparency maps into full alpha-channel */ if (png_get_valid (state, pnginfo, PNG_INFO_tRNS)) png_set_expand (state); /* downgrade 16-bit images to 8 bit */ if (bit_depth == 16) png_set_strip_16 (state); /* Handle transparency... */ if (png_get_valid(state, pnginfo, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(state); /* 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 (state); /* only if file has a file gamma, we do a correction */ if (png_get_gAMA (state, pnginfo, &file_gamma)) png_set_gamma (state, (double) 2.2, file_gamma); /* all transformations have been registered; now update pnginfo data, * get rowbytes and channels, and allocate image memory */ png_read_update_info (state, pnginfo); /* get the new color-type and bit-depth (after expansion/stripping) */ png_get_IHDR (state, pnginfo, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); /* calculate new number of channels and store alpha-presence */ if (color_type == PNG_COLOR_TYPE_RGB) channels = 3; else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) channels = 4; // else if (color_type == PNG_COLOR_TYPE_GRAY) // channels = 1; // else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) // channels = 2; else { /* GdDrawImage currently only supports 32bpp alpha channel*/ DPRINTF("GdDecodePNG: Gray image type not supported: %d\n", color_type); return NULL; } /* set image data format*/ data_format = (channels == 4)? MWIF_RGBA8888: MWIF_RGB888; //pimage->pitch = width * channels * (bit_depth / 8); //bpp = channels * 8; pmd = GdCreatePixmap(&scrdev, width, height, data_format, NULL, 0); if (!pmd) { png_destroy_read_struct(&state, &pnginfo, NULL); goto nomem; } //DPRINTF("png %dbpp\n", channels*8); if(!(rows = malloc(height * sizeof(unsigned char *)))) { png_destroy_read_struct(&state, &pnginfo, NULL); goto nomem; } for(i = 0; i < height; i++) rows[i] = ((unsigned char *)pmd->addr) + i * pmd->pitch; png_read_image(state, rows); png_read_end(state, NULL); free(rows); png_destroy_read_struct(&state, &pnginfo, NULL); return pmd; nomem: EPRINTF("GdDecodePNG: Out of memory\n"); return NULL; }
/* really_load_png: * Worker routine, used by load_png and load_memory_png. */ static ALLEGRO_BITMAP *really_load_png(png_structp png_ptr, png_infop info_ptr, int flags) { ALLEGRO_BITMAP *bmp; png_uint_32 width, height, rowbytes, real_rowbytes; int bit_depth, color_type, interlace_type; double image_gamma, screen_gamma; int intent; int bpp; int number_passes, pass; int num_trans = 0; PalEntry pal[256]; png_bytep trans; ALLEGRO_LOCKED_REGION *lock; unsigned char *buf; unsigned char *dest; bool premul = !(flags & ALLEGRO_NO_PREMULTIPLIED_ALPHA); bool index_only; ALLEGRO_ASSERT(png_ptr && info_ptr); /* 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_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ png_set_packing(png_ptr); /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ if ((color_type == PNG_COLOR_TYPE_GRAY) && (bit_depth < 8)) png_set_expand(png_ptr); /* Adds a full alpha channel if there is transparency information * in a tRNS chunk. */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { if (!(color_type & PNG_COLOR_MASK_PALETTE)) png_set_tRNS_to_alpha(png_ptr); png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); } /* Convert 16-bits per colour component to 8-bits per colour component. */ if (bit_depth == 16) png_set_strip_16(png_ptr); /* Convert grayscale to RGB triplets */ if ((color_type == PNG_COLOR_TYPE_GRAY) || (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) png_set_gray_to_rgb(png_ptr); /* Optionally, tell libpng to handle the gamma correction for us. */ if (_al_png_screen_gamma != 0.0) { screen_gamma = get_gamma(); if (png_get_sRGB(png_ptr, info_ptr, &intent)) png_set_gamma(png_ptr, screen_gamma, 0.45455); else { if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) png_set_gamma(png_ptr, screen_gamma, image_gamma); else png_set_gamma(png_ptr, screen_gamma, 0.45455); } } /* Turn on interlace handling. */ number_passes = png_set_interlace_handling(png_ptr); /* Call to gamma correct and add the background to the palette * and update info structure. */ png_read_update_info(png_ptr, info_ptr); /* Palettes. */ if (color_type & PNG_COLOR_MASK_PALETTE) { int num_palette, i; png_colorp palette; if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) { /* We don't actually dither, we just copy the palette. */ for (i = 0; ((i < num_palette) && (i < 256)); i++) { pal[i].r = palette[i].red; pal[i].g = palette[i].green; pal[i].b = palette[i].blue; } for (; i < 256; i++) pal[i].r = pal[i].g = pal[i].b = 0; } } rowbytes = png_get_rowbytes(png_ptr, info_ptr); /* Allocate the memory to hold the image using the fields of info_ptr. */ bpp = rowbytes * 8 / width; /* Allegro cannot handle less than 8 bpp. */ if (bpp < 8) bpp = 8; if ((bpp == 24) || (bpp == 32)) { #ifdef ALLEGRO_BIG_ENDIAN png_set_bgr(png_ptr); png_set_swap_alpha(png_ptr); #endif } bmp = al_create_bitmap(width, height); if (!bmp) { ALLEGRO_ERROR("al_create_bitmap failed while loading PNG.\n"); return NULL; } // TODO: can this be different from rowbytes? real_rowbytes = ((bpp + 7) / 8) * width; if (interlace_type == PNG_INTERLACE_ADAM7) buf = al_malloc(real_rowbytes * height); else buf = al_malloc(real_rowbytes); if (bpp == 8 && (color_type & PNG_COLOR_MASK_PALETTE) && (flags & ALLEGRO_KEEP_INDEX)) { lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8, ALLEGRO_LOCK_WRITEONLY); index_only = true; } else { lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, ALLEGRO_LOCK_WRITEONLY); index_only = false; } /* Read the image, one line at a time (easier to debug!) */ for (pass = 0; pass < number_passes; pass++) { png_uint_32 y; unsigned int i; unsigned char *ptr; dest = lock->data; for (y = 0; y < height; y++) { unsigned char *dest_row_start = dest; /* For interlaced pictures, the row needs to be initialized with * the contents of the previous pass. */ if (interlace_type == PNG_INTERLACE_ADAM7) ptr = buf + y * real_rowbytes; else ptr = buf; png_read_row(png_ptr, NULL, ptr); switch (bpp) { case 8: if (index_only) { for (i = 0; i < width; i++) { *(dest++) = *(ptr++); } } else if (color_type & PNG_COLOR_MASK_PALETTE) { for (i = 0; i < width; i++) { int pix = ptr[0]; ptr++; dest[0] = pal[pix].r; dest[1] = pal[pix].g; dest[2] = pal[pix].b; if (pix < num_trans) { int a = trans[pix]; dest[3] = a; if (premul) { dest[0] = dest[0] * a / 255; dest[1] = dest[1] * a / 255; dest[2] = dest[2] * a / 255; } } else { dest[3] = 255; } dest += 4; } } else { for (i = 0; i < width; i++) { int pix = ptr[0]; ptr++; *(dest++) = pix; *(dest++) = pix; *(dest++) = pix; *(dest++) = 255; } } break; case 24: for (i = 0; i < width; i++) { uint32_t pix = _AL_READ3BYTES(ptr); ptr += 3; *(dest++) = pix & 0xff; *(dest++) = (pix >> 8) & 0xff; *(dest++) = (pix >> 16) & 0xff; *(dest++) = 255; } break; case 32: for (i = 0; i < width; i++) { uint32_t pix = *(uint32_t*)ptr; int r = pix & 0xff; int g = (pix >> 8) & 0xff; int b = (pix >> 16) & 0xff; int a = (pix >> 24) & 0xff; ptr += 4; if (premul) { r = r * a / 255; g = g * a / 255; b = b * a / 255; } *(dest++) = r; *(dest++) = g; *(dest++) = b; *(dest++) = a; } break; default: ALLEGRO_ASSERT(bpp == 8 || bpp == 24 || bpp == 32); break; } dest = dest_row_start + lock->pitch; } } al_unlock_bitmap(bmp); al_free(buf); /* Read rest of file, and get additional chunks in info_ptr. */ png_read_end(png_ptr, info_ptr); return bmp; }
void PNGImageDecoder::headerAvailable() { png_structp png = m_reader->pngPtr(); png_infop info = m_reader->infoPtr(); png_uint_32 width = png_get_image_width(png, info); png_uint_32 height = png_get_image_height(png, info); // Protect against large PNGs. See http://bugzil.la/251381 for more details. const unsigned long maxPNGSize = 1000000UL; if (width > maxPNGSize || height > maxPNGSize) { longjmp(JMPBUF(png), 1); return; } // Set the image size now that the image header is available. if (!setSize(width, height)) { longjmp(JMPBUF(png), 1); return; } 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); #if USE(QCMSLIB) if ((colorType & PNG_COLOR_MASK_COLOR) && !m_ignoreGammaAndColorProfile) { // We only support color profiles for color PALETTE and RGB[A] PNG. 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 // do not 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. bool sRGB = false; ColorProfile colorProfile; getColorProfile(png, info, colorProfile, sRGB); bool imageHasAlpha = (colorType & PNG_COLOR_MASK_ALPHA) || trnsCount; m_reader->createColorTransform(colorProfile, imageHasAlpha, sRGB); m_hasColorProfile = !!m_reader->colorTransform(); } #endif if (!m_hasColorProfile) { // Deal with gamma and keep it under our control. const double inverseGamma = 0.45455; const double defaultGamma = 2.2; double gamma; if (!m_ignoreGammaAndColorProfile && png_get_gAMA(png, info, &gamma)) { const double maxGamma = 21474.83; if ((gamma <= 0.0) || (gamma > maxGamma)) { gamma = inverseGamma; png_set_gAMA(png, info, gamma); } png_set_gamma(png, defaultGamma, gamma); } else { png_set_gamma(png, defaultGamma, inverseGamma); } } // 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. #if PNG_LIBPNG_VER_MAJOR > 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 5) // '0' argument to png_process_data_pause means: Do not cache unprocessed data. m_reader->setReadOffset(m_reader->currentBufferSize() - png_process_data_pause(png, 0)); #else m_reader->setReadOffset(m_reader->currentBufferSize() - png->buffer_size); png->buffer_size = 0; #endif } }
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(png->jmpbuf, 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(png->jmpbuf, 1); return; } 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); 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 PNGImageDecoder::headerAvailable() { png_structp png = m_reader->pngPtr(); png_infop info = m_reader->infoPtr(); png_uint_32 width = png_get_image_width(png, info); png_uint_32 height = png_get_image_height(png, info); // Protect against large images. if (width > cMaxPNGSize || 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. readColorProfile(png, info, m_colorProfile); } // 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. #if defined(PNG_LIBPNG_VER_MAJOR) && defined(PNG_LIBPNG_VER_MINOR) && (PNG_LIBPNG_VER_MAJOR > 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 5)) // '0' argument to png_process_data_pause means: Do not cache unprocessed data. m_reader->setReadOffset(m_reader->currentBufferSize() - png_process_data_pause(png, 0)); #else m_reader->setReadOffset(m_reader->currentBufferSize() - png->buffer_size); png->buffer_size = 0; #endif } }
int readpng_get_image(png_containerp ctx, uint32_t *pChannels, uint32_t *pRowBytes) { double display_exponent = 2.2; // sane default double gamma; png_uint_32 i, rowbytes; png_bytepp row_pointers = NULL; /* setjmp() must be called in every function that calls a PNG-reading * libpng function */ if (setjmp(png_jmpbuf(ctx->png))) { png_destroy_read_struct(&ctx->png, &ctx->info, NULL); return -1; } /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits, * transparency chunks to full alpha channel; strip 16-bit-per-sample * images to 8 bits per sample; and convert grayscale to RGB[A] */ if (ctx->color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(ctx->png); if (ctx->color_type == PNG_COLOR_TYPE_GRAY && ctx->bit_depth < 8) png_set_expand(ctx->png); if (png_get_valid(ctx->png, ctx->info, PNG_INFO_tRNS)) png_set_expand(ctx->png); if (ctx->bit_depth == 16) png_set_strip_16(ctx->png); if (ctx->color_type == PNG_COLOR_TYPE_GRAY || ctx->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(ctx->png); /* unlike the example in the libpng documentation, we have *no* idea where * this file may have come from--so if it doesn't have a file gamma, don't * do any correction ("do no harm") */ if (png_get_gAMA(ctx->png, ctx->info, &gamma)) png_set_gamma(ctx->png, display_exponent, gamma); /* all transformations have been registered; now update ctx->info data, * get rowbytes and channels, and allocate image memory */ png_read_update_info(ctx->png, ctx->info); *pRowBytes = rowbytes = png_get_rowbytes(ctx->png, ctx->info); *pChannels = png_get_channels(ctx->png, ctx->info); if ((ctx->bytes = (uint8_t*) malloc(rowbytes*ctx->height)) == NULL) { png_destroy_read_struct(&ctx->png, &ctx->info, NULL); return -1; } if ((row_pointers = (png_bytepp)malloc(ctx->height*sizeof(png_bytep))) == NULL) { png_destroy_read_struct(&ctx->png, &ctx->info, NULL); free(ctx->bytes); ctx->bytes = NULL; return -1; } /* set the individual row_pointers to point at the correct offsets */ for (i = 0; i < ctx->height; ++i) row_pointers[i] = ctx->bytes + i*rowbytes; /* now we can go ahead and just read the whole image */ png_read_image(ctx->png, row_pointers); /* and we're done! (png_read_end() can be omitted if no processing of * post-IDAT text/time/etc. is desired) */ free(row_pointers); row_pointers = NULL; png_read_end(ctx->png, NULL); return 0; }
// load in the image data IImage* CImageLoaderPng::loadImage(io::IReadFile* file) const { #ifdef _IRR_COMPILE_WITH_LIBPNG_ if (!file) return 0; video::IImage* image = 0; //Used to point to image rows u8** RowPointers = 0; png_byte buffer[8]; // Read the first few bytes of the PNG file if( file->read(buffer, 8) != 8 ) { os::Printer::log("LOAD PNG: can't read file\n", file->getFileName(), ELL_ERROR); return 0; } // Check if it really is a PNG file if( png_sig_cmp(buffer, 0, 8) ) { os::Printer::log("LOAD PNG: not really a png\n", file->getFileName(), ELL_ERROR); return 0; } // Allocate the png read struct png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, (png_error_ptr)png_cpexcept_error, (png_error_ptr)png_cpexcept_warn); if (!png_ptr) { os::Printer::log("LOAD PNG: Internal PNG create read struct failure\n", file->getFileName(), ELL_ERROR); return 0; } // Allocate the png info struct png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { os::Printer::log("LOAD PNG: Internal PNG create info struct failure\n", file->getFileName(), ELL_ERROR); png_destroy_read_struct(&png_ptr, NULL, NULL); return 0; } // for proper error handling if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); if (RowPointers) delete [] RowPointers; return 0; } // changed by zola so we don't need to have public FILE pointers png_set_read_fn(png_ptr, file, user_read_data_fcn); png_set_sig_bytes(png_ptr, 8); // Tell png that we read the signature png_read_info(png_ptr, info_ptr); // Read the info section of the png file u32 Width; u32 Height; s32 BitDepth; s32 ColorType; { // Use temporary variables to avoid passing casted pointers png_uint_32 w,h; // Extract info png_get_IHDR(png_ptr, info_ptr, &w, &h, &BitDepth, &ColorType, NULL, NULL, NULL); Width=w; Height=h; } // Convert palette color to true color if (ColorType==PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); // Convert low bit colors to 8 bit colors if (BitDepth < 8) { if (ColorType==PNG_COLOR_TYPE_GRAY || ColorType==PNG_COLOR_TYPE_GRAY_ALPHA) png_set_expand_gray_1_2_4_to_8(png_ptr); else png_set_packing(png_ptr); } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); // Convert high bit colors to 8 bit colors if (BitDepth == 16) png_set_strip_16(png_ptr); // Convert gray color to true color if (ColorType==PNG_COLOR_TYPE_GRAY || ColorType==PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); int intent; const double screen_gamma = 2.2; if (png_get_sRGB(png_ptr, info_ptr, &intent)) png_set_gamma(png_ptr, screen_gamma, 0.45455); else { double image_gamma; if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) png_set_gamma(png_ptr, screen_gamma, image_gamma); else png_set_gamma(png_ptr, screen_gamma, 0.45455); } // Update the changes in between, as we need to get the new color type // for proper processing of the RGBA type png_read_update_info(png_ptr, info_ptr); { // Use temporary variables to avoid passing casted pointers png_uint_32 w,h; // Extract info png_get_IHDR(png_ptr, info_ptr, &w, &h, &BitDepth, &ColorType, NULL, NULL, NULL); Width=w; Height=h; } // Convert RGBA to BGRA if (ColorType==PNG_COLOR_TYPE_RGB_ALPHA) { #ifdef __BIG_ENDIAN__ png_set_swap_alpha(png_ptr); #else png_set_bgr(png_ptr); #endif } // Create the image structure to be filled by png data if (ColorType==PNG_COLOR_TYPE_RGB_ALPHA) image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(Width, Height)); else image = new CImage(ECF_R8G8B8, core::dimension2d<u32>(Width, Height)); if (!image) { os::Printer::log("LOAD PNG: Internal PNG create image struct failure\n", file->getFileName(), ELL_ERROR); png_destroy_read_struct(&png_ptr, NULL, NULL); return 0; } // Create array of pointers to rows in image data RowPointers = new png_bytep[Height]; if (!RowPointers) { os::Printer::log("LOAD PNG: Internal PNG create row pointers failure\n", file->getFileName(), ELL_ERROR); png_destroy_read_struct(&png_ptr, NULL, NULL); delete image; return 0; } // Fill array of pointers to rows in image data unsigned char* data = (unsigned char*)image->lock(); for (u32 i=0; i<Height; ++i) { RowPointers[i]=data; data += image->getPitch(); } // for proper error handling if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); delete [] RowPointers; image->unlock(); delete [] image; return 0; } // Read data using the library function that handles all transformations including interlacing png_read_image(png_ptr, RowPointers); png_read_end(png_ptr, NULL); delete [] RowPointers; image->unlock(); png_destroy_read_struct(&png_ptr,&info_ptr, 0); // Clean up memory return image; #else return 0; #endif // _IRR_COMPILE_WITH_LIBPNG_ }
void loadPng(GImage* pImage, const unsigned char* pData, size_t nDataSize) { // Check for the PNG signature if(nDataSize < 8 || png_sig_cmp((png_bytep)pData, 0, 8) != 0) throw Ex("not a png file"); // Read all PNG data up until the image data chunk. GPNGReader reader(pData); png_set_read_fn(reader.m_pReadStruct, (png_voidp)&reader, (png_rw_ptr)readFunc); png_read_info(reader.m_pReadStruct, reader.m_pInfoStruct); // Get the image data int depth, color; png_uint_32 width, height; png_get_IHDR(reader.m_pReadStruct, reader.m_pInfoStruct, &width, &height, &depth, &color, NULL, NULL, NULL); GAssert(depth == 8); // unexpected depth pImage->setSize(width, height); // Set gamma correction double dGamma; if (png_get_gAMA(reader.m_pReadStruct, reader.m_pInfoStruct, &dGamma)) png_set_gamma(reader.m_pReadStruct, 2.2, dGamma); else png_set_gamma(reader.m_pReadStruct, 2.2, 1.0 / 2.2); // 1.0 = viewing gamma, 2.2 = screen gamma // Update the 'info' struct with the gamma information png_read_update_info(reader.m_pReadStruct, reader.m_pInfoStruct); // Tell it to expand palettes to full channels png_set_expand(reader.m_pReadStruct); png_set_gray_to_rgb(reader.m_pReadStruct); // Allocate the row pointers unsigned long rowbytes = png_get_rowbytes(reader.m_pReadStruct, reader.m_pInfoStruct); unsigned long channels = rowbytes / width; ArrayHolder<unsigned char> hData(new unsigned char[rowbytes * height]); png_bytep pRawData = (png_bytep)hData.get(); unsigned int i; { ArrayHolder<unsigned char> hRows(new unsigned char[sizeof(png_bytep) * height]); png_bytep* pRows = (png_bytep*)hRows.get(); for(i = 0; i < height; i++) pRows[i] = pRawData + i * rowbytes; png_read_image(reader.m_pReadStruct, pRows); } // Copy to the GImage unsigned long nPixels = width * height; unsigned int* pRGBQuads = pImage->pixels(); unsigned char *pBytes = pRawData; if(channels > 3) { GAssert(channels == 4); // unexpected number of channels for(i = 0; i < nPixels; i++) { *pRGBQuads = gARGB(pBytes[3], pBytes[0], pBytes[1], pBytes[2]); pBytes += channels; pRGBQuads++; } } else if(channels == 3) { for(i = 0; i < nPixels; i++) { *pRGBQuads = gARGB(0xff, pBytes[0], pBytes[1], pBytes[2]); pBytes += channels; pRGBQuads++; } } else { throw Ex("Sorry, loading ", to_str(channels), "-channel pngs not supported"); /* GAssert(channels == 1); // unexpected number of channels for(i = 0; i < nPixels; i++) { *pRGBQuads = gARGB(0xff, pBytes[0], pBytes[0], pBytes[0]); pBytes += channels; pRGBQuads++; }*/ } // Check for additional tags png_read_end(reader.m_pReadStruct, reader.m_pEndInfoStruct); }
int rwpng_read_image(FILE *infile, mainprog_info *mainprog_ptr) { png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_uint_32 i, rowbytes; int color_type, bit_depth; uch sig[8]; /* first do a quick check that the file really is a PNG image; could * have used slightly more general png_sig_cmp() function instead */ fread(sig, 1, 8, infile); if (!png_check_sig(sig, 8)) { mainprog_ptr->retval = 21; /* bad signature */ return mainprog_ptr->retval; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, mainprog_ptr, rwpng_error_handler, NULL); if (!png_ptr) { mainprog_ptr->retval = 24; /* out of memory */ return mainprog_ptr->retval; } mainprog_ptr->png_ptr = png_ptr; info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); mainprog_ptr->retval = 24; /* out of memory */ return mainprog_ptr->retval; } mainprog_ptr->info_ptr = info_ptr; /* GRR TO DO: use end_info struct */ /* we could create a second info struct here (end_info), but it's only * useful if we want to keep pre- and post-IDAT chunk info separated * (mainly for PNG-aware image editors and converters) */ /* setjmp() must be called in every function that calls a non-trivial * libpng function */ if (setjmp(mainprog_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); mainprog_ptr->retval = 25; /* fatal libpng error (via longjmp()) */ return mainprog_ptr->retval; } png_init_io(png_ptr, infile); png_set_sig_bytes(png_ptr, 8); /* we already read the 8 signature bytes */ png_read_info(png_ptr, info_ptr); /* read all PNG info up to image data */ /* alternatively, could make separate calls to png_get_image_width(), * etc., but want bit_depth and color_type for later [don't care about * compression_type and filter_type => NULLs] */ png_get_IHDR(png_ptr, info_ptr, &mainprog_ptr->width, &mainprog_ptr->height, &bit_depth, &color_type, &mainprog_ptr->interlaced, NULL, NULL); /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits, * transparency chunks to full alpha channel; strip 16-bit-per-sample * images to 8 bits per sample; and convert grayscale to RGB[A] */ /* GRR TO DO: handle each of GA, RGB, RGBA without conversion to RGBA */ /* GRR TO DO: allow sub-8-bit quantization? */ /* GRR TO DO: preserve all safe-to-copy ancillary PNG chunks */ /* GRR TO DO: get and map background color? */ if (!(color_type & PNG_COLOR_MASK_ALPHA)) { #ifdef PNG_READ_FILLER_SUPPORTED /* GRP: expand palette to RGB, and grayscale or RGB to GA or RGBA */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); png_set_filler(png_ptr, 65535L, PNG_FILLER_AFTER); #else fprintf(stderr, "pngquant readpng: image is neither RGBA nor GA\n"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); mainprog_ptr->retval = 26; return mainprog_ptr->retval; #endif } /* if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); */ /* GRR TO DO: handle 16-bps data natively? */ if (bit_depth == 16) png_set_strip_16(png_ptr); /* GRR TO DO: probably want to handle this separately, without expansion */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); /* get and save the gamma info (if any) for writing */ mainprog_ptr->gamma = 0.0; png_get_gAMA(png_ptr, info_ptr, &mainprog_ptr->gamma); /* 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); mainprog_ptr->rowbytes = rowbytes = png_get_rowbytes(png_ptr, info_ptr); mainprog_ptr->channels = (int)png_get_channels(png_ptr, info_ptr); if ((mainprog_ptr->rgba_data = (uch *)malloc(rowbytes*mainprog_ptr->height)) == NULL) { fprintf(stderr, "pngquant readpng: unable to allocate image data\n"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); mainprog_ptr->retval = 24; return mainprog_ptr->retval; } if ((mainprog_ptr->row_pointers = (png_bytepp)malloc(mainprog_ptr->height*sizeof(png_bytep))) == NULL) { fprintf(stderr, "pngquant readpng: unable to allocate row pointers\n"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); free(mainprog_ptr->rgba_data); mainprog_ptr->rgba_data = NULL; mainprog_ptr->retval = 24; return mainprog_ptr->retval; } Trace((stderr, "readpng_get_image: channels = %d, rowbytes = %ld, height = %ld\n", mainprog_ptr->channels, rowbytes, mainprog_ptr->height)); /* set the individual row_pointers to point at the correct offsets */ for (i = 0; i < mainprog_ptr->height; ++i) mainprog_ptr->row_pointers[i] = mainprog_ptr->rgba_data + i*rowbytes; /* now we can go ahead and just read the whole image */ png_read_image(png_ptr, (png_bytepp)mainprog_ptr->row_pointers); /* and we're done! (png_read_end() can be omitted if no processing of * post-IDAT text/time/etc. is desired) */ png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); mainprog_ptr->png_ptr = NULL; mainprog_ptr->info_ptr = NULL; mainprog_ptr->retval = 0; return 0; }
static void png_info_callback(png_structp png_ptr, png_infop info_ptr) { int bit_depth, color_type, intent; double gamma; int bytes_per_pixel=3; struct cached_image *cimg; cimg=global_cimg; bit_depth=png_get_bit_depth(png_ptr, info_ptr); color_type=png_get_color_type(png_ptr, info_ptr); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)){ png_set_expand(png_ptr); /* Legacy version of png_set_tRNS_to_alpha(png_ptr); */ bytes_per_pixel++; } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); if (bit_depth==16){ #ifndef REPACK_16 #ifdef C_LITTLE_ENDIAN /* We use native endianity only if unsigned short is 2-byte * because otherwise we have to reassemble the buffer so we * will leave in the libpng-native big endian. */ png_set_swap(png_ptr); #endif /* #ifdef C_LITTLE_ENDIAN */ #endif /* #ifndef REPACK_16 */ bytes_per_pixel*=sizeof(unsigned short); } png_set_interlace_handling(png_ptr); if (color_type==PNG_COLOR_TYPE_RGB_ALPHA ||color_type==PNG_COLOR_TYPE_GRAY_ALPHA){ if (bytes_per_pixel==3 ||bytes_per_pixel==3*sizeof(unsigned short)) bytes_per_pixel=4*bytes_per_pixel/3; } cimg->width=png_get_image_width(png_ptr,info_ptr); cimg->height=png_get_image_height(png_ptr,info_ptr); cimg->buffer_bytes_per_pixel=bytes_per_pixel; if (png_get_sRGB(png_ptr, info_ptr, &intent)){ gamma=sRGB_gamma; } else { if (!png_get_gAMA(png_ptr, info_ptr, &gamma)){ gamma=sRGB_gamma; } } cimg->red_gamma=gamma; cimg->green_gamma=gamma; cimg->blue_gamma=gamma; png_read_update_info(png_ptr,info_ptr); cimg->strip_optimized=0; if (header_dimensions_known(cimg)) img_my_png_error(png_ptr, "bad image size"); }
/*--------------------------------------------------------------------------- Loads a PNG file. Image : Image will be returned there. Path : Path to image file, relative to the current working directory. Gamma : Display gamma to apply on textures, 2.2 is typical. ---------------------------------------------------------------------------*/ void PNG::Load(Texture &Image, const std::string &Path, float Gamma) { Destroy(); //Important - set class to reading mode Mode = PNG::ModeRead; #if defined (WINDOWS) if (fopen_s(&File, Path.c_str(), "rb") != 0) {throw dexception("Failed to open file: %s.", Path.c_str());} #else File = fopen(Path.c_str(), "rb"); if (File == nullptr) {throw dexception("Failed to open file: %s.", Path.c_str());} #endif uint8 Header[PNG::HeaderSize]; if (fread((png_bytep)Header, 1, PNG::HeaderSize, File) == 0) {throw dexception("fread( ) failed.");} if (!png_check_sig(Header, PNG::HeaderSize)) {throw dexception("Not a valid PNG file.");} PngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (PngPtr == nullptr) {throw dexception("png_create_read_struct( ) failed.");} InfoPtr = png_create_info_struct(PngPtr); if (InfoPtr == nullptr) {throw dexception("png_create_info_struct( ) failed.");} if (setjmp(png_jmpbuf(PngPtr))) {throw dexception("setjmp( ) failed.");} //Read into structures png_init_io(PngPtr, File); png_set_sig_bytes(PngPtr, PNG::HeaderSize); png_read_info(PngPtr, InfoPtr); //Determine image attributes vector2<png_uint_32> Res; int BitDepth, ColourType; png_get_IHDR(PngPtr, InfoPtr, &Res.U, &Res.V, &BitDepth, &ColourType, nullptr, nullptr, nullptr); Texture::TexType Type = Texture::TypeRGB; switch (ColourType) { case PNG_COLOR_TYPE_GRAY : if (BitDepth < 8) { Type = Texture::TypeLum; png_set_expand_gray_1_2_4_to_8(PngPtr); } else if (BitDepth == 16) { Type = Texture::TypeDepth; } break; case PNG_COLOR_TYPE_GRAY_ALPHA : Type = Texture::TypeRGBA; png_set_gray_to_rgb(PngPtr); break; case PNG_COLOR_TYPE_PALETTE : Type = Texture::TypeRGB; png_set_palette_to_rgb(PngPtr); break; case PNG_COLOR_TYPE_RGB : Type = Texture::TypeRGB; png_set_strip_alpha(PngPtr); //If libpng reports RGB, make sure we completely strip alpha break; case PNG_COLOR_TYPE_RGB_ALPHA : Type = Texture::TypeRGBA; break; default : throw dexception("Unknown colour type."); } //Convert palette alpha into a separate alpha channel if (png_get_valid(PngPtr, InfoPtr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(PngPtr); if (ColourType == PNG_COLOR_TYPE_PALETTE) {Type = Texture::TypeRGBA;} } //Force 8 bit per channel if (BitDepth >= 16) { if (Type != Texture::TypeDepth) {png_set_strip_16(PngPtr);} } else if (BitDepth < 8) { png_set_packing(PngPtr); } //Specify display and file gamma (assume 0.45455 for missing file gamma) double FileGamma; if (!png_get_gAMA(PngPtr, InfoPtr, &FileGamma)) {FileGamma = 0.45455;} png_set_gamma(PngPtr, Gamma, FileGamma); //Swap byte order for int16 values on big endian machines if ((BitDepth >= 16) && !Math::MachineLittleEndian()) {png_set_swap(PngPtr);} //Apply the above transformation settings png_read_update_info(PngPtr, InfoPtr); //Allocate image Image.Create(cast_vector2(uint, Res), Type); if (Image.GetBytesPerLine() < (usize)png_get_rowbytes(PngPtr, InfoPtr)) {throw dexception("Incorrect scan line size for allocated image.");} //Populate row pointer array Rows.Create((usize)Res.V); for (uiter I = 0; I < (usize)Res.V; I++) { Rows[I] = Image.Address(0, I); } //Decode png_read_image(PngPtr, Rows.Pointer()); png_read_end(PngPtr, InfoPtr); //Clean up Destroy(); }
int APIENTRY pngLoadF(FILE *fp, int mipmap, int trans, pngInfo *pinfo) { GLint pack, unpack; unsigned char header[8]; png_structp png; png_infop info; png_infop endinfo; png_bytep data, data2; png_bytep *row_p; double fileGamma; png_uint_32 width, height, rw, rh; int depth, color; png_uint_32 i; fread(header, 1, 8, fp); if (!png_check_sig(header, 8)) return 0; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info = png_create_info_struct(png); endinfo = png_create_info_struct(png); // DH: added following lines if (setjmp(png->jmpbuf)) { png_destroy_read_struct(&png, &info, &endinfo); return 0; } // ~DH png_init_io(png, fp); png_set_sig_bytes(png, 8); png_read_info(png, info); png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL); if (pinfo != NULL) { pinfo->Width = width; pinfo->Height = height; pinfo->Depth = depth; } if (MaxTextureSize == 0) glGetIntegerv(GL_MAX_TEXTURE_SIZE, &MaxTextureSize); #ifdef SUPPORTS_PALETTE_EXT #ifdef _WIN32 if (PalettedTextures == -1) PalettedTextures = ExtSupported("GL_EXT_paletted_texture") && (strstr((const char *) glGetString(GL_VERSION), "1.1.0 3Dfx Beta") == NULL); if (PalettedTextures) { if (glColorTableEXT == NULL) { glColorTableEXT = (PFNGLCOLORTABLEEXTPROC) wglGetProcAddress("glColorTableEXT"); if (glColorTableEXT == NULL) PalettedTextures = 0; } } #endif #endif if (PalettedTextures == -1) PalettedTextures = 0; if (color == PNG_COLOR_TYPE_GRAY || color == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); if (color&PNG_COLOR_MASK_ALPHA && trans != PNG_ALPHA) { png_set_strip_alpha(png); color &= ~PNG_COLOR_MASK_ALPHA; } if (!(PalettedTextures && mipmap >= 0 && trans == PNG_SOLID)) if (color == PNG_COLOR_TYPE_PALETTE) png_set_expand(png); /*--GAMMA--*/ checkForGammaEnv(); if (png_get_gAMA(png, info, &fileGamma)) png_set_gamma(png, screenGamma, fileGamma); else png_set_gamma(png, screenGamma, 1.0/2.2); png_read_update_info(png, info); data = (png_bytep) malloc(png_get_rowbytes(png, info)*height); row_p = (png_bytep *) malloc(sizeof(png_bytep)*height); for (i = 0; i < height; i++) { if (StandardOrientation) row_p[height - 1 - i] = &data[png_get_rowbytes(png, info)*i]; else row_p[i] = &data[png_get_rowbytes(png, info)*i]; } png_read_image(png, row_p); free(row_p); rw = SafeSize(width), rh = SafeSize(height); if (rw != width || rh != height) { const int channels = png_get_rowbytes(png, info)/width; data2 = (png_bytep) malloc(rw*rh*channels); /* Doesn't work on certain sizes */ /* if (gluScaleImage(glformat, width, height, GL_UNSIGNED_BYTE, data, rw, rh, GL_UNSIGNED_BYTE, data2) != 0) return 0; */ Resize(channels, data, width, height, data2, rw, rh); width = rw, height = rh; free(data); data = data2; } { /* OpenGL stuff */ glGetIntegerv(GL_PACK_ALIGNMENT, &pack); glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack); glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); #ifdef SUPPORTS_PALETTE_EXT if (PalettedTextures && mipmap >= 0 && trans == PNG_SOLID && color == PNG_COLOR_TYPE_PALETTE) { png_colorp pal; int cols; GLint intf; if (pinfo != NULL) pinfo->Alpha = 0; png_get_PLTE(png, info, &pal, &cols); switch (cols) { case 1<<1: intf = GL_COLOR_INDEX1_EXT; break; case 1<<2: intf = GL_COLOR_INDEX2_EXT; break; case 1<<4: intf = GL_COLOR_INDEX4_EXT; break; case 1<<8: intf = GL_COLOR_INDEX8_EXT; break; case 1<<12: intf = GL_COLOR_INDEX12_EXT; break; case 1<<16: intf = GL_COLOR_INDEX16_EXT; break; default: /*printf("Warning: Colour depth %i not recognised\n", cols);*/ return 0; } glColorTableEXT(GL_TEXTURE_2D, GL_RGB8, cols, GL_RGB, GL_UNSIGNED_BYTE, pal); glTexImage2D(GL_TEXTURE_2D, mipmap, intf, width, height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, data); } else #endif if (trans == PNG_SOLID || trans == PNG_ALPHA || trans == PNG_LUMINANCEALPHA || color == PNG_COLOR_TYPE_RGB_ALPHA || color == PNG_COLOR_TYPE_GRAY_ALPHA) { GLenum glformat; GLint glcomponent; switch (color) { case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_PALETTE: glformat = GL_RGB; glcomponent = 3; if (pinfo != NULL) pinfo->Alpha = 0; break; case PNG_COLOR_TYPE_GRAY_ALPHA: case PNG_COLOR_TYPE_RGB_ALPHA: glformat = GL_RGBA; glcomponent = 4; if (pinfo != NULL) pinfo->Alpha = 8; break; default: /*puts("glformat not set");*/ return 0; } if (trans == PNG_LUMINANCEALPHA) glformat = GL_LUMINANCE_ALPHA; if (mipmap == PNG_BUILDMIPMAPS) Build2DMipmaps(glcomponent, width, height, glformat, data, 1); else if (mipmap == PNG_SIMPLEMIPMAPS) Build2DMipmaps(glcomponent, width, height, glformat, data, 0); else glTexImage2D(GL_TEXTURE_2D, mipmap, glcomponent, width, height, 0, glformat, GL_UNSIGNED_BYTE, data); } else { png_bytep p, endp, q; int r, g, b, a; p = data, endp = p+width*height*3; q = data2 = (png_bytep) malloc(sizeof(png_byte)*width*height*4); if (pinfo != NULL) pinfo->Alpha = 8; #define FORSTART \ do { \ r = *p++; /*red */ \ g = *p++; /*green*/ \ b = *p++; /*blue */ \ *q++ = r; \ *q++ = g; \ *q++ = b; #define FOREND \ q++; \ } while (p != endp); #define ALPHA *q switch (trans) { case PNG_CALLBACK: FORSTART ALPHA = AlphaCallback((unsigned char) r, (unsigned char) g, (unsigned char) b); FOREND break; case PNG_STENCIL: FORSTART if (r == StencilRed && g == StencilGreen && b == StencilBlue) ALPHA = 0; else ALPHA = 255; FOREND break; case PNG_BLEND1: FORSTART a = r+g+b; if (a > 255) ALPHA = 255; else ALPHA = a; FOREND break; case PNG_BLEND2: FORSTART a = r+g+b; if (a > 255*2) ALPHA = 255; else ALPHA = a/2; FOREND break; case PNG_BLEND3: FORSTART ALPHA = (r+g+b)/3; FOREND break; case PNG_BLEND4: FORSTART a = r*r+g*g+b*b; if (a > 255) ALPHA = 255; else ALPHA = a; FOREND break; case PNG_BLEND5: FORSTART a = r*r+g*g+b*b; if (a > 255*2) ALPHA = 255; else ALPHA = a/2; FOREND break; case PNG_BLEND6: FORSTART a = r*r+g*g+b*b; if (a > 255*3) ALPHA = 255; else ALPHA = a/3; FOREND break; //HACK: disabling this for now /* case PNG_BLEND7: FORSTART a = r*r+g*g+b*b; if (a > 255*255) ALPHA = 255; else ALPHA = (int) (sqrt(float(a))); FOREND */ break; } #undef FORSTART #undef FOREND #undef ALPHA if (mipmap == PNG_BUILDMIPMAPS) Build2DMipmaps(4, width, height, GL_RGBA, data2, 1); else if (mipmap == PNG_SIMPLEMIPMAPS) Build2DMipmaps(4, width, height, GL_RGBA, data2, 0); else glTexImage2D(GL_TEXTURE_2D, mipmap, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2); free(data2); } glPixelStorei(GL_PACK_ALIGNMENT, pack); glPixelStorei(GL_UNPACK_ALIGNMENT, unpack); } /* OpenGL end */ png_read_end(png, endinfo); png_destroy_read_struct(&png, &info, &endinfo); free(data); return 1; }
int APIENTRY pngLoadRawF(FILE *fp, pngRawInfo *pinfo) { unsigned char header[8]; png_structp png; png_infop info; png_infop endinfo; png_bytep data; png_bytep *row_p; double fileGamma; png_uint_32 width, height; int depth, color; png_uint_32 i; if (pinfo == NULL) return 0; fread(header, 1, 8, fp); if (!png_check_sig(header, 8)) return 0; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info = png_create_info_struct(png); endinfo = png_create_info_struct(png); // DH: added following lines if (setjmp(png->jmpbuf)) { png_destroy_read_struct(&png, &info, &endinfo); return 0; } // ~DH png_init_io(png, fp); png_set_sig_bytes(png, 8); png_read_info(png, info); png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL); pinfo->Width = width; pinfo->Height = height; pinfo->Depth = depth; /*--GAMMA--*/ checkForGammaEnv(); if (png_get_gAMA(png, info, &fileGamma)) png_set_gamma(png, screenGamma, fileGamma); else png_set_gamma(png, screenGamma, 1.0/2.2); png_read_update_info(png, info); data = (png_bytep) malloc(png_get_rowbytes(png, info)*height); row_p = (png_bytep *) malloc(sizeof(png_bytep)*height); for (i = 0; i < height; i++) { if (StandardOrientation) row_p[height - 1 - i] = &data[png_get_rowbytes(png, info)*i]; else row_p[i] = &data[png_get_rowbytes(png, info)*i]; } png_read_image(png, row_p); free(row_p); if (color == PNG_COLOR_TYPE_PALETTE) { int cols; png_get_PLTE(png, info, (png_colorp *) &pinfo->Palette, &cols); } else { pinfo->Palette = NULL; } if (color&PNG_COLOR_MASK_ALPHA) { if (color&PNG_COLOR_MASK_PALETTE || color == PNG_COLOR_TYPE_GRAY_ALPHA) pinfo->Components = 2; else pinfo->Components = 4; pinfo->Alpha = 8; } else { if (color&PNG_COLOR_MASK_PALETTE || color == PNG_COLOR_TYPE_GRAY) pinfo->Components = 1; else pinfo->Components = 3; pinfo->Alpha = 0; } pinfo->Data = data; png_read_end(png, endinfo); png_destroy_read_struct(&png, &info, &endinfo); return 1; }
BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file, volatile BOOL raw, BOOL alpha) { png_struct *png_ptr = NULL; png_info *info_ptr = NULL; png_byte buf[8]; png_byte *png_pixels = NULL; png_byte **row_pointers = NULL; png_byte *pix_ptr = NULL; png_uint_32 row_bytes; png_uint_32 width; png_uint_32 height; int bit_depth; int channels; int color_type; int alpha_present; int row, col; int ret; int i; long dep_16; /* read and check signature in PNG file */ ret = fread (buf, 1, 8, png_file); if (ret != 8) return FALSE; ret = png_sig_cmp (buf, 0, 8); if (ret) return FALSE; /* create png and info structures */ png_ptr = png_create_read_struct (png_get_libpng_ver(NULL), NULL, NULL, NULL); if (!png_ptr) return FALSE; /* out of memory */ info_ptr = png_create_info_struct (png_ptr); if (!info_ptr) { png_destroy_read_struct (&png_ptr, NULL, NULL); return FALSE; /* out of memory */ } if (setjmp (png_jmpbuf(png_ptr))) { png_destroy_read_struct (&png_ptr, &info_ptr, NULL); return FALSE; } /* set up the input control for C streams */ png_init_io (png_ptr, png_file); png_set_sig_bytes (png_ptr, 8); /* we already read the 8 signature bytes */ /* read the file information */ png_read_info (png_ptr, info_ptr); /* get size and bit-depth of the PNG-image */ png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); /* set-up the transformations */ /* transform paletted images into full-color rgb */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand (png_ptr); /* expand images to bit-depth 8 (only applicable for grayscale images) */ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand (png_ptr); /* transform transparency maps into full alpha-channel */ if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand (png_ptr); #ifdef NJET /* downgrade 16-bit images to 8-bit */ if (bit_depth == 16) png_set_strip_16 (png_ptr); /* transform grayscale images into full-color */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb (png_ptr); /* only if file has a file gamma, we do a correction */ if (png_get_gAMA (png_ptr, info_ptr, &file_gamma)) png_set_gamma (png_ptr, (double) 2.2, file_gamma); #endif /* all transformations have been registered; now update info_ptr data, * get rowbytes and channels, and allocate image memory */ png_read_update_info (png_ptr, info_ptr); /* get the new color-type and bit-depth (after expansion/stripping) */ png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); /* check for 16-bit files */ if (bit_depth == 16) { raw = FALSE; #ifdef __TURBOC__ pnm_file->flags &= ~((unsigned) _F_BIN); #endif } /* calculate new number of channels and store alpha-presence */ if (color_type == PNG_COLOR_TYPE_GRAY) channels = 1; else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) channels = 2; else if (color_type == PNG_COLOR_TYPE_RGB) channels = 3; else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) channels = 4; else channels = 0; /* should never happen */ alpha_present = (channels - 1) % 2; /* check if alpha is expected to be present in file */ if (alpha && !alpha_present) { fprintf (stderr, "PNG2PNM\n"); fprintf (stderr, "Error: PNG-file doesn't contain alpha channel\n"); exit (1); } /* row_bytes is the width x number of channels x (bit-depth / 8) */ row_bytes = png_get_rowbytes (png_ptr, info_ptr); if ((png_pixels = (png_byte *) malloc (row_bytes * height * sizeof (png_byte))) == NULL) { png_destroy_read_struct (&png_ptr, &info_ptr, NULL); return FALSE; } if ((row_pointers = (png_byte **) malloc (height * sizeof (png_bytep))) == NULL) { png_destroy_read_struct (&png_ptr, &info_ptr, NULL); free (png_pixels); png_pixels = NULL; return FALSE; } /* set the individual row_pointers to point at the correct offsets */ for (i = 0; i < ((int) height); i++) row_pointers[i] = png_pixels + i * row_bytes; /* now we can go ahead and just read the whole image */ png_read_image (png_ptr, row_pointers); /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end (png_ptr, info_ptr); /* clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp) NULL); /* write header of PNM file */ if ((color_type == PNG_COLOR_TYPE_GRAY) || (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) { fprintf (pnm_file, "%s\n", (raw) ? "P5" : "P2"); fprintf (pnm_file, "%d %d\n", (int) width, (int) height); fprintf (pnm_file, "%ld\n", ((1L << (int) bit_depth) - 1L)); } else if ((color_type == PNG_COLOR_TYPE_RGB) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA)) { fprintf (pnm_file, "%s\n", (raw) ? "P6" : "P3"); fprintf (pnm_file, "%d %d\n", (int) width, (int) height); fprintf (pnm_file, "%ld\n", ((1L << (int) bit_depth) - 1L)); } /* write header of PGM file with alpha channel */ if ((alpha) && ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA))) { fprintf (alpha_file, "%s\n", (raw) ? "P5" : "P2"); fprintf (alpha_file, "%d %d\n", (int) width, (int) height); fprintf (alpha_file, "%ld\n", ((1L << (int) bit_depth) - 1L)); } /* write data to PNM file */ pix_ptr = png_pixels; for (row = 0; row < (int) height; row++) { for (col = 0; col < (int) width; col++) { for (i = 0; i < (channels - alpha_present); i++) { if (raw) fputc ((int) *pix_ptr++ , pnm_file); else if (bit_depth == 16){ dep_16 = (long) *pix_ptr++; fprintf (pnm_file, "%ld ", (dep_16 << 8) + ((long) *pix_ptr++)); } else fprintf (pnm_file, "%ld ", (long) *pix_ptr++); } if (alpha_present) { if (!alpha) { pix_ptr++; /* alpha */ if (bit_depth == 16) pix_ptr++; } else /* output alpha-channel as pgm file */ { if (raw) fputc ((int) *pix_ptr++ , alpha_file); else if (bit_depth == 16){ dep_16 = (long) *pix_ptr++; fprintf (alpha_file, "%ld ", (dep_16 << 8) + (long) *pix_ptr++); } else fprintf (alpha_file, "%ld ", (long) *pix_ptr++); } } /* if alpha_present */ if (!raw) if (col % 4 == 3) fprintf (pnm_file, "\n"); } /* end for col */ if (!raw) if (col % 4 != 0) fprintf (pnm_file, "\n"); } /* end for row */ if (row_pointers != (unsigned char**) NULL) free (row_pointers); if (png_pixels != (unsigned char*) NULL) free (png_pixels); return TRUE; } /* end of source */