// // validate our input // static void s_PngReadValidate(png_structp png_ptr, png_infop info_ptr, size_t& width, size_t& height, size_t& depth, size_t& x, size_t& y, size_t& w, size_t& h) { // store and validate our image's parameters width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); depth = png_get_channels(png_ptr, info_ptr); png_byte color_type = png_get_color_type(png_ptr, info_ptr); png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr); // we support only RGB and RGBA images if ( color_type != PNG_COLOR_TYPE_RGB && color_type != PNG_COLOR_TYPE_RGB_ALPHA ) { string msg("CImageIOPng::ReadImage(): unhandled color type: "); msg += NStr::NumericToString((int)color_type); NCBI_THROW(CImageException, eReadError, msg); } // ...and only with a bit depth of 8 if (bit_depth != 8) { string msg("CImageIOPng::ReadImage(): unhandled bit depth: "); msg += NStr::NumericToString((int)bit_depth); NCBI_THROW(CImageException, eReadError, msg); } // this goes along with RGB or RGBA if (depth != 3 && depth != 4) { string msg("CImageIOPng::ReadImage(): unhandled image channels: "); msg += NStr::NumericToString((int)depth); NCBI_THROW(CImageException, eReadError, msg); } if (x != (size_t)-1 && y != (size_t)-1 && w != (size_t)-1 && h != (size_t)-1) { // further validation: make sure we're actually on the image if (x >= width || y >= height) { string msg("CImageIOPng::ReadImage(): invalid starting position: "); msg += NStr::NumericToString(x); msg += ", "; msg += NStr::NumericToString(y); NCBI_THROW(CImageException, eReadError, msg); } // clamp our width and height to the image size if (x + w >= width) { w = width - x; LOG_POST_X(27, Warning << "CImageIOPng::ReadImage(): clamped width to " << w); } if (y + h >= height) { h = height - y; LOG_POST_X(28, Warning << "CImageIOPng::ReadImage(): clamped height to " << h); } } png_read_update_info(png_ptr, info_ptr); }
static void read_png_file_low(const char* file_name, png_image_data_t *png_image_data) { png_structp png_ptr; int number_of_passes; char header[8]; // 8 is the maximum size that can be checked int y; /* open file and test for it being a png */ FILE *fp = fopen(file_name, "rb"); if (!fp) abort_("[read_png_file] File %s could not be opened for reading", file_name); fread(header, 1, 8, fp); if (png_sig_cmp(header, 0, 8)) abort_("[read_png_file] File %s is not recognized as a PNG file", file_name); /* initialize stuff */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) abort_("[read_png_file] png_create_read_struct failed"); png_image_data->info_ptr = png_create_info_struct(png_ptr); if (!png_image_data->info_ptr) abort_("[read_png_file] png_create_info_struct failed"); if (setjmp(png_jmpbuf(png_ptr))) abort_("[read_png_file] Error during init_io"); png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); /* 8 == sig_read ? */ png_read_info(png_ptr, png_image_data->info_ptr); /* set transformations */ /* if ((png_image_data->info_ptr->color_type & PNG_COLOR_TYPE_RGB) == 0) transforms |= PNG_TRANSFORM_BGR; */ if (png_get_valid(png_ptr, png_image_data->info_ptr, PNG_INFO_sBIT)) { png_color_8p sig_bit; png_get_sBIT(png_ptr, png_image_data->info_ptr, &sig_bit); printf("sig_bit: %d\n", sig_bit); png_set_shift(png_ptr, sig_bit); } /* TODO DFG: is this needed? */ number_of_passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, png_image_data->info_ptr); /* read file */ if (setjmp(png_jmpbuf(png_ptr))) abort_("[read_png_file] Error during read_image"); #if 1 png_image_data->row_pointers = (png_bytep*) qemu_malloc(sizeof(png_bytep) * png_image_data->info_ptr->height); for (y=0; y < png_image_data->info_ptr->height; y++) png_image_data->row_pointers[y] = (png_byte*) qemu_malloc(png_image_data->info_ptr->rowbytes); png_read_image(png_ptr, png_image_data->row_pointers); #endif /* DFG TODO: Cleanup */ /* png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); */ fclose(fp); }
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); // 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 ((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. readColorProfile(png, info, m_colorProfile); #if USE(QCMSLIB) bool decodedImageHasAlpha = (colorType & PNG_COLOR_MASK_ALPHA) || trnsCount; m_reader->createColorTransform(m_colorProfile, decodedImageHasAlpha); m_colorProfile.clear(); #endif } // 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 } }
SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src) { SDL_Surface *volatile surface; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int bit_depth, color_type, interlace_type; Uint32 Rmask; Uint32 Gmask; Uint32 Bmask; Uint32 Amask; SDL_Palette *palette; png_bytep *volatile row_pointers; int row, i; volatile int ckey = -1; png_color_16 *transv; /* Initialize the data we will clean up when we're done */ png_ptr = NULL; info_ptr = NULL; row_pointers = NULL; surface = NULL; /* Check to make sure we have something to do */ if ( ! src ) { goto done; } /* Create the PNG loading context structure */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,NULL,NULL); if (png_ptr == NULL){ IMG_SetError("Couldn't allocate memory for PNG file"); goto done; } /* Allocate/initialize the memory for image information. REQUIRED. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { IMG_SetError("Couldn't create image information for PNG file"); goto done; } /* Set error handling if you are using setjmp/longjmp method (this is * the normal method of doing things with libpng). REQUIRED unless you * set up your own error handlers in png_create_read_struct() earlier. */ if ( setjmp(png_ptr->jmpbuf) ) { IMG_SetError("Error reading the PNG file."); goto done; } /* Set up the input control */ png_set_read_fn(png_ptr, src, png_read_data); /* Read PNG header info */ png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); /* tell libpng to strip 16 bit/color files down to 8 bits/color */ 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). */ png_set_packing(png_ptr); /* scale greyscale values to the range 0..255 */ if(color_type == PNG_COLOR_TYPE_GRAY) png_set_expand(png_ptr); /* For images with a single "transparent colour", set colour key; if more than one index has transparency, or if partially transparent entries exist, use full alpha channel */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { int num_trans; Uint8 *trans; png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &transv); if(color_type == PNG_COLOR_TYPE_PALETTE) { /* Check if all tRNS entries are opaque except one */ int i, t = -1; for(i = 0; i < num_trans; i++) if(trans[i] == 0) { if(t >= 0) break; t = i; } else if(trans[i] != 255) break; if(i == num_trans) { /* exactly one transparent index */ ckey = t; } else { /* more than one transparent index, or translucency */ png_set_expand(png_ptr); } } else ckey = 0; /* actual value will be set later */ } if ( color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) png_set_gray_to_rgb(png_ptr); png_read_update_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); /* Allocate the SDL surface to hold the image */ Rmask = Gmask = Bmask = Amask = 0 ; if ( color_type != PNG_COLOR_TYPE_PALETTE ) { if ( SDL_BYTEORDER == SDL_LIL_ENDIAN ) { Rmask = 0x000000FF; Gmask = 0x0000FF00; Bmask = 0x00FF0000; Amask = (info_ptr->channels == 4) ? 0xFF000000 : 0; } else { int s = (info_ptr->channels == 4) ? 0 : 8; Rmask = 0xFF000000 >> s; Gmask = 0x00FF0000 >> s; Bmask = 0x0000FF00 >> s; Amask = 0x000000FF >> s; } } surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, bit_depth*info_ptr->channels, Rmask,Gmask,Bmask,Amask); if ( surface == NULL ) { IMG_SetError("Out of memory"); goto done; } if(ckey != -1) { if(color_type != PNG_COLOR_TYPE_PALETTE) /* FIXME: Should these be truncated or shifted down? */ ckey = SDL_MapRGB(surface->format, (Uint8)transv->red, (Uint8)transv->green, (Uint8)transv->blue); SDL_SetColorKey(surface, SDL_SRCCOLORKEY, ckey); } /* Create the array of pointers to image data */ row_pointers = (png_bytep*) malloc(sizeof(png_bytep)*height); if ( (row_pointers == NULL) ) { IMG_SetError("Out of memory"); SDL_FreeSurface(surface); surface = NULL; goto done; } for (row = 0; row < (int)height; row++) { row_pointers[row] = (png_bytep) (Uint8 *)surface->pixels + row*surface->pitch; } /* Read the entire image in one go */ png_read_image(png_ptr, row_pointers); /* read rest of file, get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); /* Load the palette, if any */ palette = surface->format->palette; if ( palette ) { if(color_type == PNG_COLOR_TYPE_GRAY) { palette->ncolors = 256; for(i = 0; i < 256; i++) { palette->colors[i].r = i; palette->colors[i].g = i; palette->colors[i].b = i; } } else if (info_ptr->num_palette > 0 ) { palette->ncolors = info_ptr->num_palette; for( i=0; i<info_ptr->num_palette; ++i ) { palette->colors[i].b = info_ptr->palette[i].blue; palette->colors[i].g = info_ptr->palette[i].green; palette->colors[i].r = info_ptr->palette[i].red; } } } done: /* Clean up and return */ png_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : (png_infopp)0, (png_infopp)0); if ( row_pointers ) { free(row_pointers); } return(surface); }
static gint gegl_buffer_import_png (GeglBuffer *gegl_buffer, GInputStream *stream, gint dest_x, gint dest_y, gint *ret_width, gint *ret_height, const Babl *format, // can be NULL GError **err) { gint width; gint bit_depth; gint bpp; gint number_of_passes=1; png_uint_32 w; png_uint_32 h; png_structp load_png_ptr; png_infop load_info_ptr; guchar *pixels; /*png_bytep *rows;*/ unsigned int i; png_bytep *row_p = NULL; g_return_val_if_fail(stream, -1); if (!check_valid_png_header(stream, err)) { return -1; } load_png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, error_fn, NULL); if (!load_png_ptr) { return -1; } load_info_ptr = png_create_info_struct (load_png_ptr); if (!load_info_ptr) { png_destroy_read_struct (&load_png_ptr, &load_info_ptr, NULL); return -1; } if (setjmp (png_jmpbuf (load_png_ptr))) { png_destroy_read_struct (&load_png_ptr, &load_info_ptr, NULL); g_free (row_p); return -1; } png_set_read_fn(load_png_ptr, stream, read_fn); png_set_sig_bytes (load_png_ptr, 8); // we already read header png_read_info (load_png_ptr, load_info_ptr); { int color_type; int interlace_type; png_get_IHDR (load_png_ptr, load_info_ptr, &w, &h, &bit_depth, &color_type, &interlace_type, NULL, NULL); width = w; if (ret_width) *ret_width = w; if (ret_height) *ret_height = h; if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { png_set_expand (load_png_ptr); bit_depth = 8; } if (png_get_valid (load_png_ptr, load_info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha (load_png_ptr); color_type |= PNG_COLOR_MASK_ALPHA; } switch (color_type) { case PNG_COLOR_TYPE_GRAY: bpp = 1; break; case PNG_COLOR_TYPE_GRAY_ALPHA: bpp = 2; break; case PNG_COLOR_TYPE_RGB: bpp = 3; break; case PNG_COLOR_TYPE_RGB_ALPHA: bpp = 4; break; case (PNG_COLOR_TYPE_PALETTE | PNG_COLOR_MASK_ALPHA): bpp = 4; break; case PNG_COLOR_TYPE_PALETTE: bpp = 3; break; default: g_warning ("color type mismatch"); png_destroy_read_struct (&load_png_ptr, &load_info_ptr, NULL); return -1; } if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb (load_png_ptr); if (bit_depth == 16) bpp = bpp << 1; if (!format) format = get_babl_format(bit_depth, color_type); #if BYTE_ORDER == LITTLE_ENDIAN if (bit_depth == 16) png_set_swap (load_png_ptr); #endif if (interlace_type == PNG_INTERLACE_ADAM7) number_of_passes = png_set_interlace_handling (load_png_ptr); if (png_get_valid (load_png_ptr, load_info_ptr, PNG_INFO_gAMA)) { gdouble gamma; png_get_gAMA (load_png_ptr, load_info_ptr, &gamma); png_set_gamma (load_png_ptr, 2.2, gamma); } else { png_set_gamma (load_png_ptr, 2.2, 0.45455); } png_read_update_info (load_png_ptr, load_info_ptr); } pixels = g_malloc0 (width*bpp); { gint pass; GeglRectangle rect; for (pass=0; pass<number_of_passes; pass++) { for(i=0; i<h; i++) { gegl_rectangle_set (&rect, 0, i, width, 1); if (pass != 0) gegl_buffer_get (gegl_buffer, &rect, 1.0, format, pixels, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); png_read_rows (load_png_ptr, &pixels, NULL, 1); gegl_buffer_set (gegl_buffer, &rect, 0, format, pixels, GEGL_AUTO_ROWSTRIDE); } } } png_read_end (load_png_ptr, NULL); png_destroy_read_struct (&load_png_ptr, &load_info_ptr, NULL); g_free (pixels); return 0; }
static int readpng( FILE *f, GrContext *grc, int use_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 color_type; int alpha_present; int i, x, y, r, g, b; int alpha = 0, ro, go, bo; int maxwidth, maxheight; GrColor *pColors = NULL; /* is it a PNG file? */ if( fread( buf,1,8,f ) != 8 ) return -1; if( ! png_check_sig( buf,8 ) ) return -1; png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); if( !png_ptr ){ return -1; } info_ptr = png_create_info_struct( png_ptr ); if( !info_ptr ){ png_destroy_read_struct( &png_ptr,NULL,NULL ); return -1; } if( setjmp( png_jmpbuf(png_ptr) ) ){ png_destroy_read_struct( &png_ptr,&info_ptr,NULL ); return -1; } png_init_io( png_ptr,f ); png_set_sig_bytes( png_ptr,8 ); png_read_info( png_ptr,info_ptr ); png_get_IHDR( png_ptr,info_ptr,&width,&height,&bit_depth, &color_type,NULL,NULL,NULL); /* tell libpng to strip 16 bit/color files down to 8 bits/color */ if( bit_depth == 16 ) png_set_strip_16( png_ptr ); /* expand paletted colors into true RGB triplets */ if( color_type == PNG_COLOR_TYPE_PALETTE ) png_set_expand( 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 ); /* expand paletted or RGB images with transparency to full alpha channels so the data will be available as RGBA quartets. */ if( png_get_valid( png_ptr,info_ptr,PNG_INFO_tRNS ) ) png_set_expand( png_ptr ); /* transform grayscale images into rgb */ if( color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) png_set_gray_to_rgb( png_ptr ); /* we don't do gamma correction by now */ png_read_update_info( png_ptr,info_ptr ); png_get_IHDR( png_ptr,info_ptr,&width,&height,&bit_depth, &color_type,NULL,NULL,NULL); if( color_type == PNG_COLOR_TYPE_RGB ) alpha_present = 0; else if( color_type == PNG_COLOR_TYPE_RGB_ALPHA ) alpha_present = 1; else{ png_destroy_read_struct( &png_ptr,&info_ptr,NULL ); return -1; } row_bytes = png_get_rowbytes( png_ptr,info_ptr ); png_pixels = (png_byte *) malloc( row_bytes * height * sizeof(png_byte) ); if( png_pixels == NULL ){ png_destroy_read_struct( &png_ptr,&info_ptr,NULL ); return -1; } row_pointers = (png_byte **) malloc( height * sizeof(png_bytep) ); if( row_pointers == NULL ){ png_destroy_read_struct( &png_ptr,&info_ptr,NULL ); free( png_pixels ); png_pixels = NULL; return -1; } for( i=0; i<height; i++ ) row_pointers[i] = png_pixels + i * row_bytes; png_read_image (png_ptr, row_pointers); png_read_end (png_ptr, info_ptr); png_destroy_read_struct( &png_ptr,&info_ptr,NULL ); /* write data to context */ maxwidth = (width > GrSizeX()) ? GrSizeX() : width; maxheight = (height > GrSizeY()) ? GrSizeY() : height; pColors = malloc( maxwidth * sizeof(GrColor) ); if( pColors == NULL ){ free( row_pointers ); row_pointers = NULL; free( png_pixels ); png_pixels = NULL; return -1; } for( y=0; y<maxheight; y++ ){ pix_ptr = row_pointers[y]; if( alpha_present && use_alpha ){ memcpy( pColors,GrGetScanline( 0,maxwidth-1,y ), sizeof(GrColor)*maxwidth ); } for( x=0; x<width; x++ ){ r = *pix_ptr++; g = *pix_ptr++; b = *pix_ptr++; alpha = 0; if( alpha_present ) alpha = *pix_ptr++; if( x < maxwidth ){ if( alpha_present && use_alpha ){ if (alpha == 0) { GrQueryColor( pColors[x],&r,&g,&b ); } else if (alpha != 255) { // if a==255, rgb not modified float f1, f2; f1 = (alpha/255.0); f2 = ((255-alpha)/255.0); GrQueryColor( pColors[x],&ro,&go,&bo ); r = (r * f1) + (ro * f2); g = (g * f1) + (go * f2); b = (b * f1) + (bo * f2); } } pColors[x] = GrAllocColor( r,g,b ); } } GrPutScanline( 0,maxwidth-1,y,pColors,GrWRITE ); } if( pColors) free( pColors ); if( row_pointers ) free( row_pointers ); if( png_pixels ) free( png_pixels ); return 0; }
png_byte *Texture::load(char* filename, int &width, int &height) { png_byte header[8]; //open file as binary FILE *fp = fopen(filename, "rb"); if (!fp) { return TEXTURE_LOAD_ERROR; } //read the header fread(header, 1, 8, fp); //test if png int is_png = !png_sig_cmp(header, 0, 8); if (!is_png) { fclose(fp); return TEXTURE_LOAD_ERROR; } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fclose(fp); return TEXTURE_LOAD_ERROR; } 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); return TEXTURE_LOAD_ERROR; } 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); return (TEXTURE_LOAD_ERROR); } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return (TEXTURE_LOAD_ERROR); } png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); int bit_depth, color_type; png_uint_32 twidth, theight; png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type, NULL, NULL, NULL); width = twidth; height = theight; png_read_update_info(png_ptr, info_ptr); int rowbytes = png_get_rowbytes(png_ptr, info_ptr); png_byte *image_data = new png_byte[rowbytes * height]; if (!image_data) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return TEXTURE_LOAD_ERROR; } png_bytep *row_pointers = new png_bytep[height]; if (!row_pointers) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); delete[] image_data; fclose(fp); return TEXTURE_LOAD_ERROR; } // Does OpenGL really need the inverted row-based format? // Seems as it doesn't, maybe myth or rumor? // row_pointers[height - 1 - i] = image_data + i * rowbytes; for (int i = 0; i < height; ++i) { row_pointers[i] = image_data + i * rowbytes; } png_read_image(png_ptr, row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); delete[] row_pointers; fclose(fp); return image_data; }
// *image_data_ptr should be deleted with free() // return value of 1 == success. int pngLoad(const char *file, int *pwidth, int *pheight, unsigned char **image_data_ptr, bool flip) { FILE *infile = fopen(file, "rb"); if (!infile) { printf("No such file: %s\n", file); return 0; } /* Check for the 8-byte signature */ char sig[8]; /* PNG signature array */ int len = fread(sig, 1, 8, infile); if (len != 8 || !png_check_sig((unsigned char *) sig, 8)) { fclose(infile); return 0; } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fclose(infile); return 4; /* out of memory */ } 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(infile); return 4; /* out of memory */ } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(infile); return 0; } png_init_io(png_ptr, infile); png_set_sig_bytes(png_ptr, 8); // we already checked the sig bytes png_read_info(png_ptr, info_ptr); int bit_depth=0; int color_type=0; png_uint_32 width=0, height=0; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); *pwidth = (int)width; *pheight = (int)height; // Set up some transforms. Always load RGBA. if (color_type & PNG_COLOR_MASK_ALPHA) { // png_set_strip_alpha(png_ptr); } if (bit_depth > 8) { 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); } if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } if (color_type == PNG_COLOR_TYPE_RGB) { png_set_filler(png_ptr, 255, PNG_FILLER_AFTER); } // Update the png info struct. png_read_update_info(png_ptr, info_ptr); unsigned long rowbytes = png_get_rowbytes(png_ptr, info_ptr); unsigned char *image_data = NULL; /* raw png image data */ if ((image_data = (unsigned char *) malloc(rowbytes * height))==NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return 4; } png_bytepp row_pointers = NULL; if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); free(image_data); image_data = NULL; return 4; } if (flip) { for (unsigned long i = 0; i < height; ++i) row_pointers[height - 1 - i] = (png_byte *)(image_data + i*rowbytes); } else { for (unsigned long i = 0; i < height; ++i) row_pointers[i] = (png_byte *)(image_data + i*rowbytes); } png_read_image(png_ptr, row_pointers); free(row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(infile); *image_data_ptr = image_data; return 1; }
uint8 *readpng_get_image(uint32 *pChannels, uint32 *pRowbytes, uint32 *pWidth, uint32 *pHeight) { png_uint_32 width, height; int bit_depth, color_type; uint8 *image_data = NULL; png_uint_32 i, rowbytes; png_bytepp row_pointers = NULL; /* 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, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); *pWidth = width; *pHeight = height; /* 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 (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); /* 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); *pRowbytes = rowbytes = png_get_rowbytes(png_ptr, info_ptr); *pChannels = (int)png_get_channels(png_ptr, info_ptr); if ((image_data = (uint8 *)malloc(rowbytes*height)) == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); free(image_data); image_data = NULL; return NULL; } Trace((stderr, "readpng_get_image: channels = %d, rowbytes = %ld, height = %ld\n", *pChannels, rowbytes, height)); /* set the individual row_pointers to point at the correct offsets */ for (i = 0; i < height; ++i) row_pointers[i] = image_data + i*rowbytes; /* now we can go ahead and just read the whole image */ png_read_image(png_ptr, row_pointers); free(row_pointers); row_pointers = NULL; png_read_end(png_ptr, NULL); return image_data; }
static GstFlowReturn gst_pngdec_caps_create_and_set (GstPngDec * pngdec) { GstFlowReturn ret = GST_FLOW_OK; GstCaps *caps = NULL, *res = NULL; GstPadTemplate *templ = NULL; gint bpc = 0, color_type; png_uint_32 width, height; g_return_val_if_fail (GST_IS_PNGDEC (pngdec), GST_FLOW_ERROR); /* Get bits per channel */ bpc = png_get_bit_depth (pngdec->png, pngdec->info); /* We don't handle 16 bits per color, strip down to 8 */ if (bpc == 16) { GST_LOG_OBJECT (pngdec, "this is a 16 bits per channel PNG image, strip down to 8 bits"); png_set_strip_16 (pngdec->png); } /* Get Color type */ color_type = png_get_color_type (pngdec->png, pngdec->info); #if 0 /* We used to have this HACK to reverse the outgoing bytes, but the problem * that originally required the hack seems to have been in ffmpegcolorspace's * RGBA descriptions. It doesn't seem needed now that's fixed, but might * still be needed on big-endian systems, I'm not sure. J.S. 6/7/2007 */ if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) png_set_bgr (pngdec->png); #endif /* Gray scale converted to RGB and upscaled to 8 bits */ if ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA) || (color_type == PNG_COLOR_TYPE_GRAY)) { GST_LOG_OBJECT (pngdec, "converting grayscale png to RGB"); png_set_gray_to_rgb (pngdec->png); if (bpc < 8) { /* Convert to 8 bits */ GST_LOG_OBJECT (pngdec, "converting grayscale image to 8 bits"); png_set_gray_1_2_4_to_8 (pngdec->png); } } /* Palette converted to RGB */ if (color_type == PNG_COLOR_TYPE_PALETTE) { GST_LOG_OBJECT (pngdec, "converting palette png to RGB"); png_set_palette_to_rgb (pngdec->png); } /* Update the info structure */ png_read_update_info (pngdec->png, pngdec->info); /* Get IHDR header again after transformation settings */ png_get_IHDR (pngdec->png, pngdec->info, &width, &height, &bpc, &pngdec->color_type, NULL, NULL, NULL); pngdec->width = width; pngdec->height = height; GST_LOG_OBJECT (pngdec, "this is a %dx%d PNG image", pngdec->width, pngdec->height); switch (pngdec->color_type) { case PNG_COLOR_TYPE_RGB: GST_LOG_OBJECT (pngdec, "we have no alpha channel, depth is 24 bits"); pngdec->bpp = 24; break; case PNG_COLOR_TYPE_RGB_ALPHA: GST_LOG_OBJECT (pngdec, "we have an alpha channel, depth is 32 bits"); pngdec->bpp = 32; break; default: GST_ELEMENT_ERROR (pngdec, STREAM, NOT_IMPLEMENTED, (NULL), ("pngdec does not support this color type")); ret = GST_FLOW_NOT_SUPPORTED; goto beach; } caps = gst_caps_new_simple ("video/x-raw-rgb", "width", G_TYPE_INT, pngdec->width, "height", G_TYPE_INT, pngdec->height, "bpp", G_TYPE_INT, pngdec->bpp, "framerate", GST_TYPE_FRACTION, pngdec->fps_n, pngdec->fps_d, NULL); templ = gst_static_pad_template_get (&gst_pngdec_src_pad_template); res = gst_caps_intersect (caps, gst_pad_template_get_caps (templ)); gst_caps_unref (caps); gst_object_unref (templ); if (!gst_pad_set_caps (pngdec->srcpad, res)) ret = GST_FLOW_NOT_NEGOTIATED; GST_DEBUG_OBJECT (pngdec, "our caps %" GST_PTR_FORMAT, res); gst_caps_unref (res); /* Push a newsegment event */ if (pngdec->need_newsegment) { gst_pad_push_event (pngdec->srcpad, gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0)); pngdec->need_newsegment = FALSE; } beach: return ret; }
bool PngDecoder::readData( Mat& img ) { volatile bool result = false; AutoBuffer<uchar*> _buffer(m_height); uchar** buffer = _buffer; int color = img.channels() > 1; 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_set_interlace_handling( png_ptr ); png_read_update_info( png_ptr, info_ptr ); for( y = 0; y < m_height; y++ ) buffer[y] = img.data + y*img.step; png_read_image( png_ptr, buffer ); png_read_end( png_ptr, end_info ); result = true; } } close(); return result; }
gfx_t *gfx_load_png(char *filename) { gfx_t *gfx = 0; int i, x, y; png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_infop end_info = NULL; png_uint_32 width, height, rowbytes; int bit_depth, color_type; png_byte *image_data = 0; png_bytep *row_pointers = 0; uint8_t sig[8]; FILE *infile; infile = fopen(filename, "rb"); if (!infile) { fprintf(stderr, "cant open `%s`\n", filename); return 0; } if (0) { fail: if (gfx) free(gfx); if (image_data) free(image_data); if (row_pointers) free(row_pointers); fclose(infile); return 0; } fread(sig, 1, 8, infile); if (!png_check_sig(sig, 8)) { fprintf(stderr, "bad signature for `%s`\n", filename); return 0; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fprintf(stderr, "png_create_info_struct: out of memory for `%s`\n", filename); goto fail; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); fprintf(stderr, "png_create_info_struct: out of memory for `%s`\n", filename); goto fail; } end_info = png_create_info_struct(png_ptr); if (!end_info) { fprintf(stderr, "error: png_create_info_struct returned 0.\n"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); goto fail; } // setjmp() must be called in every function that calls a PNG-reading libpng function if (setjmp(png_jmpbuf(png_ptr))) { jmpbuf_fail: png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); goto fail; } png_init_io(png_ptr, infile); png_set_sig_bytes(png_ptr, 8); // tell libpng that 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); png_read_update_info(png_ptr, info_ptr); rowbytes = png_get_rowbytes(png_ptr, info_ptr); image_data = malloc(rowbytes * height * sizeof(png_byte)+15); if (!image_data) { fprintf(stderr, "load_png: could not allocate memory for PNG image data\n"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); goto jmpbuf_fail; } row_pointers = malloc(height * sizeof(png_bytep)); if (!row_pointers) { fprintf(stderr, "load_png: could not allocate memory for PNG row pointers\n"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); goto jmpbuf_fail; } for (y = 0; y < height; y++) { row_pointers[height - 1 - y] = image_data + y * rowbytes; } png_read_image(png_ptr, row_pointers); if (bit_depth != 8 && bit_depth != 16 && color_type != PNG_COLOR_TYPE_PALETTE) { fprintf(stderr, "load_png: unsupported bit_depth=%d\n", bit_depth); goto fail; } if (color_type == PNG_COLOR_TYPE_RGB) { //RGB gfx = new_gfx(width, height); if (bit_depth == 8) { for (y = 0; y < height; y++) { png_byte *row = row_pointers[y]; for (x = 0; x < width; x++) { gfx_set(gfx, x, y, R8G8B8(row[0], row[1], row[2])); row += 3; } } } else { for (y = 0; y < height; y++) { png_byte *row = row_pointers[y]; for (x = 0; x < width; x++) { gfx_set(gfx, x, y, R8G8B8(row[1], row[3], row[5])); row += 6; } } } } else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) { gfx = new_gfx(width, height); if (bit_depth == 8) { for (y = 0; y < height; y++) { png_byte *row = row_pointers[y]; for (x = 0; x < width; x++) { gfx_set(gfx, x, y, R8G8B8A8(row[0], row[1], row[2], 0xFF-row[3])); row += 4; } } } else { for (y = 0; y < height; y++) { png_byte *row = row_pointers[y]; for (x = 0; x < width; x++) { gfx_set(gfx, x, y, R8G8B8A8(row[1], row[3], row[5], 0xFF-row[7])); row += 8; } } } } else if (color_type == PNG_COLOR_TYPE_PALETTE) { uint32_t cmap[GFX_CMAP_SIZE]; png_colorp palette; int num_palette; // palette size png_bytep trans; int num_trans; png_color_16p trans_values; gfx = new_gfx(width, height); if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette) == 0) { fprintf(stderr, "load_png: couldn't retrieve palette\n"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); goto fail; } if (png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values) == 0) { num_trans = 0; } for (i = 0; i < num_palette; i++) { int a = i < num_trans ? 0xFF - trans[i] : 0; cmap[i] = R8G8B8A8(palette[i].red, palette[i].green, palette[i].blue, a); } gfx_set_cmap(gfx, cmap); if (bit_depth == 8) { for (y = 0; y < height; y++) { png_byte *row = row_pointers[y]; for (x = 0; x < width; x++) { gfx_set(gfx, x, y, row[0]); row++; } } } else if (bit_depth == 4) { for (y = 0; y < height; y++) { png_byte *row = row_pointers[y]; for (x = 0; x < width; ) { png_byte c = row[0]; for (i = 4; i >=0 ; i-=4) { gfx_set(gfx, x, y, (c>>i)&0xF); if (++x == width) break; } row++; } } } else if (bit_depth == 2) {
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 > (png_uint_32)cMaxPNGSize || png->height > (png_uint_32)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); // 1/6/10 CSidhall - Added it as a param setting option bool gammaOn = IsGammaCorrectionActive(); if(gammaOn) { // EA/Alex Mole: Don't bother with this as it *always* causes extra work // which we (Criterion) never need //// 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; } }
static vita2d_texture *_vita2d_load_PNG_generic(const void *io_ptr, png_rw_ptr read_data_fn) { png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { goto error_create_read; } png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { goto error_create_info; } png_bytep *row_ptrs = NULL; if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)0); if (row_ptrs != NULL) free(row_ptrs); return NULL; } png_set_read_fn(png_ptr, (png_voidp)io_ptr, read_data_fn); png_set_sig_bytes(png_ptr, PNG_SIGSIZE); png_read_info(png_ptr, info_ptr); unsigned int width, height; int bit_depth, color_type; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); if ((color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8) || (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) || png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) || (bit_depth == 16)) { png_set_expand(png_ptr); } if (bit_depth == 16) png_set_scale_16(png_ptr); if (bit_depth == 8 && color_type == PNG_COLOR_TYPE_RGB) png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); } if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); png_read_update_info(png_ptr, info_ptr); row_ptrs = (png_bytep *)malloc(sizeof(png_bytep) * height); if (!row_ptrs) goto error_alloc_rows; vita2d_texture *texture = vita2d_create_empty_texture(width, height); if (!texture) goto error_create_tex; void *texture_data = vita2d_texture_get_datap(texture); unsigned int stride = vita2d_texture_get_stride(texture); int i; for (i = 0; i < height; i++) { row_ptrs[i] = (png_bytep)(texture_data + i*stride); } png_read_image(png_ptr, row_ptrs); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)0); free(row_ptrs); return texture; error_create_tex: free(row_ptrs); error_alloc_rows: png_destroy_info_struct(png_ptr, &info_ptr); error_create_info: png_destroy_read_struct(&png_ptr, (png_infopp)0, (png_infopp)0); error_create_read: return NULL; }
int read_header(const char *filename, dt_imageio_png_t *png) { png->f = g_fopen(filename, "rb"); if(!png->f) return 1; #define NUM_BYTES_CHECK (8) png_byte dat[NUM_BYTES_CHECK]; size_t cnt = fread(dat, 1, NUM_BYTES_CHECK, png->f); if(cnt != NUM_BYTES_CHECK || png_sig_cmp(dat, (png_size_t)0, NUM_BYTES_CHECK)) { fclose(png->f); return 1; } png->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png->png_ptr) { fclose(png->f); return 1; } png->info_ptr = png_create_info_struct(png->png_ptr); if(!png->info_ptr) { fclose(png->f); png_destroy_read_struct(&png->png_ptr, NULL, NULL); return 1; } if(setjmp(png_jmpbuf(png->png_ptr))) { fclose(png->f); png_destroy_read_struct(&png->png_ptr, &png->info_ptr, NULL); return 1; } png_init_io(png->png_ptr, png->f); // we checked some bytes png_set_sig_bytes(png->png_ptr, NUM_BYTES_CHECK); // image info png_read_info(png->png_ptr, png->info_ptr); png->bit_depth = png_get_bit_depth(png->png_ptr, png->info_ptr); png->color_type = png_get_color_type(png->png_ptr, png->info_ptr); // image input transformations // palette => rgb if(png->color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png->png_ptr); // 1, 2, 4 bit => 8 bit if(png->color_type == PNG_COLOR_TYPE_GRAY && png->bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png->png_ptr); png->bit_depth = 8; } // strip alpha channel if(png->color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png->png_ptr); // grayscale => rgb if(png->color_type == PNG_COLOR_TYPE_GRAY || png->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png->png_ptr); // reflect changes png_read_update_info(png->png_ptr, png->info_ptr); // png->bytespp = 3*bit_depth/8; png->width = png_get_image_width(png->png_ptr, png->info_ptr); png->height = png_get_image_height(png->png_ptr, png->info_ptr); #undef NUM_BYTES_CHECK return 0; }
char * load_png(char *name, int *width, int *height) { FILE *png_file = fopen(name, "rb"); assert(png_file); uint8_t header[PNG_SIG_BYTES]; fread(header, 1, PNG_SIG_BYTES, png_file); assert(!png_sig_cmp(header, 0, PNG_SIG_BYTES)); png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); assert(png_ptr); png_infop info_ptr = png_create_info_struct(png_ptr); assert(info_ptr); png_infop end_info = png_create_info_struct(png_ptr); assert(end_info); assert(!setjmp(png_jmpbuf(png_ptr))); png_init_io(png_ptr, png_file); png_set_sig_bytes(png_ptr, PNG_SIG_BYTES); png_read_info(png_ptr, info_ptr); *width = png_get_image_width(png_ptr, info_ptr); *height = png_get_image_height(png_ptr, info_ptr); png_uint_32 bit_depth, color_type; 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_GRAY && bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); if(color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); else 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)) png_set_tRNS_to_alpha(png_ptr); else png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); png_read_update_info(png_ptr, info_ptr); png_uint_32 rowbytes = png_get_rowbytes(png_ptr, info_ptr); png_uint_32 numbytes = rowbytes*(*height); png_byte* pixels = malloc(numbytes); png_byte** row_ptrs = malloc((*height) * sizeof(png_byte*)); int i; for (i=0; i<(*height); i++) row_ptrs[i] = pixels + ((*height) - 1 - i)*rowbytes; png_read_image(png_ptr, row_ptrs); free(row_ptrs); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(png_file); return (char *)pixels; }
bool initSludge (char * filename) { int a = 0; mouseCursorAnim = makeNullAnim (); FILE * fp = openAndVerify (filename, 'G', 'E', ERROR_BAD_HEADER, gameVersion); if (! fp) return false; if (fgetc (fp)) { numBIFNames = get2bytes (fp); allBIFNames = new char * [numBIFNames]; if (! checkNew (allBIFNames)) return false; for (int fn = 0; fn < numBIFNames; fn ++) { allBIFNames[fn] = readString (fp); } numUserFunc = get2bytes (fp); allUserFunc = new char * [numUserFunc]; if (! checkNew (allUserFunc)) return false; for (int fn = 0; fn < numUserFunc; fn ++) { allUserFunc[fn] = readString (fp); } if (gameVersion >= VERSION(1,3)) { numResourceNames = get2bytes (fp); allResourceNames = new char * [numResourceNames]; if (! checkNew (allResourceNames)) return false; for (int fn = 0; fn < numResourceNames; fn ++) { allResourceNames[fn] = readString (fp); } } } winWidth = get2bytes (fp); winHeight = get2bytes (fp); specialSettings = fgetc (fp); desiredfps = 1000/fgetc (fp); delete[] readString (fp); // Unused - was used for registration purposes. size_t bytes_read = fread (& fileTime, sizeof (FILETIME), 1, fp); if (bytes_read != sizeof (FILETIME) && ferror (fp)) { debugOut("Reading error in initSludge.\n"); } char * dataFol = (gameVersion >= VERSION(1,3)) ? readString(fp) : joinStrings ("", ""); gameSettings.numLanguages = (gameVersion >= VERSION(1,3)) ? (fgetc (fp)) : 0; makeLanguageTable (fp); if (gameVersion >= VERSION(1,6)) { fgetc(fp); // aaLoad fgetc (fp); getFloat (fp); getFloat (fp); } char * checker = readString (fp); if (strcmp (checker, "okSoFar")) return fatal (ERROR_BAD_HEADER, filename); delete checker; checker = NULL; unsigned char customIconLogo = fgetc (fp); if (customIconLogo & 1) { // There is an icon - read it! int n; long file_pointer = ftell (fp); png_structp png_ptr; png_infop info_ptr, end_info; int fileIsPNG = true; // Is this a PNG file? char tmp[10]; bytes_read = fread(tmp, 1, 8, fp); if (bytes_read != 8 && ferror (fp)) { debugOut("Reading error in initSludge.\n"); } if (png_sig_cmp((png_byte *) tmp, 0, 8)) { // No, it's old-school HSI fileIsPNG = false; fseek(fp, file_pointer, SEEK_SET); iconW = get2bytes (fp); iconH = get2bytes (fp); } else { // Read the PNG header png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { return false; } 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; } end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return false; } 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); iconW = width; iconH = height; 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); } gameIcon = new unsigned char [iconW*iconH*4]; if (! gameIcon) return fatal ("Can't reserve memory for game icon."); int32_t transCol = 63519; Uint8 *p = (Uint8 *) gameIcon; if (fileIsPNG) { unsigned char * row_pointers[iconH]; for (int i = 0; i<iconH; i++) row_pointers[i] = p + 4*i*iconW; 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); } else { for (int t2 = 0; t2 < iconH; t2 ++) { int t1 = 0; while (t1 < iconW) { unsigned short c = (unsigned short) get2bytes (fp); if (c & 32) { n = fgetc (fp) + 1; c -= 32; } else { n = 1; } while (n --) { *p++ = (Uint8) redValue(c); *p++ = (Uint8) greenValue(c); *p++ = (Uint8) blueValue(c); *p++ = (Uint8) (c == transCol) ? 0 : 255; t1++; } } } } } if (customIconLogo & 2) { // There is an logo - read it! int n; long file_pointer = ftell (fp); png_structp png_ptr; png_infop info_ptr, end_info; int fileIsPNG = true; // Is this a PNG file? char tmp[10]; bytes_read = fread(tmp, 1, 8, fp); if (bytes_read != 8 && ferror (fp)) { debugOut("Reading error in initSludge.\n"); } if (png_sig_cmp((png_byte *) tmp, 0, 8)) { // No, it's old-school HSI fileIsPNG = false; fseek(fp, file_pointer, SEEK_SET); logoW = get2bytes (fp); logoH = get2bytes (fp); } else { // Read the PNG header png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { return false; } 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; } end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return false; } 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); logoW = width; logoH = height; 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); #ifdef WIN32 // Windows wants a BGR bitmap if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) png_set_bgr(png_ptr); #endif 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); } if ((logoW != 310) || (logoH != 88)) return fatal ("Game logo have wrong dimensions. (Should be 310x88)"); gameLogo = new unsigned char [logoW*logoH*4]; if (! gameLogo) return fatal ("Can't reserve memory for game logo."); // int32_t transCol = 63519; Uint8 *p = (Uint8 *) gameLogo; if (fileIsPNG) { unsigned char * row_pointers[logoH]; for (int i = 0; i<logoH; i++) row_pointers[i] = p + 4*i*logoW; 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); } else { for (int t2 = 0; t2 < logoH; t2 ++) { int t1 = 0; while (t1 < logoW) { unsigned short c = (unsigned short) get2bytes (fp); if (c & 32) { n = fgetc (fp) + 1; c -= 32; } else { n = 1; } while (n --) { #ifdef WIN32 // Windows wants a BGR bitmap *p++ = (Uint8) blueValue(c); *p++ = (Uint8) greenValue(c); *p++ = (Uint8) redValue(c); #else *p++ = (Uint8) redValue(c); *p++ = (Uint8) greenValue(c); *p++ = (Uint8) blueValue(c); #endif *p++ = (Uint8) /*(c == transCol) ? 0 :*/ 255; t1++; } } } } } numGlobals = get2bytes (fp); globalVars = new variable[numGlobals]; if (! checkNew (globalVars)) return false; for (a = 0; a < numGlobals; a ++) initVarNew (globalVars[a]); // Get the original (untranslated) name of the game and convert it to Unicode. // We use this to find saved preferences and saved games. setFileIndices (fp, gameSettings.numLanguages, 0); char * gameNameOrig = getNumberedString(1); char * gameName = encodeFilename (gameNameOrig); delete gameNameOrig; changeToUserDir (); #ifdef _WIN32 mkdir (gameName); #else mkdir (gameName, 0000777); #endif if (chdir (gameName)) return fatal ("This game's preference folder is inaccessible!\nI can't access the following directory (maybe there's a file with the same name, or maybe it's read-protected):", gameName); delete [] gameName; // Get user settings readIniFile (filename); // There's no startup window on Linux and respecting this // option from the ini file would disable commandline options. #if defined __unix__ && !(defined __APPLE__) if (! showSetupWindow()) return 0; saveIniFile (filename); #else if (! gameSettings.noStartWindow) { if (! showSetupWindow()) return 0; saveIniFile (filename); } #endif // Now set file indices properly to the chosen language. languageNum = getLanguageForFileB (); if (languageNum < 0) return fatal ("Can't find the translation data specified!"); setFileIndices (NULL, gameSettings.numLanguages, languageNum); if (dataFol[0]) { char *dataFolder = encodeFilename(dataFol); #ifdef _WIN32 mkdir (dataFolder); #else mkdir (dataFolder, 0000777); #endif if (chdir (dataFolder)) return fatal ("This game's data folder is inaccessible!\nI can't access the following directory (maybe there's a file with the same name, or maybe it's read-protected):", dataFolder); delete dataFolder; } positionStatus (10, winHeight - 15); return true; }
color_image_t * color_image_png_load( FILE* fp, const char* file_name ) { // read the header png_byte header[8]; fread(header, 1, 8, fp); if (png_sig_cmp(header, 0, 8)) { fprintf(stderr, "error: %s is not a PNG.\n", file_name); fclose(fp); return 0; } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fprintf(stderr, "error: png_create_read_struct returned 0.\n"); fclose(fp); return 0; } // create png info struct png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { fprintf(stderr, "error: png_create_info_struct returned 0.\n"); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); fclose(fp); return 0; } // create png info struct png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { fprintf(stderr, "error: png_create_info_struct returned 0.\n"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); fclose(fp); return 0; } // the code in this if statement gets called if libpng encounters an error if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr, "error from libpng\n"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return 0; } // init png reading png_init_io(png_ptr, fp); // let libpng know you already read the first 8 bytes png_set_sig_bytes(png_ptr, 8); // read all the info up to the image data png_read_info(png_ptr, info_ptr); // variables to pass to get info int bit_depth, color_type; png_uint_32 temp_width, temp_height; // get info about png png_get_IHDR(png_ptr, info_ptr, &temp_width, &temp_height, &bit_depth, &color_type, NULL, NULL, NULL); // Update the png info struct. png_read_update_info(png_ptr, info_ptr); // Row size in bytes. int rowbytes = png_get_rowbytes(png_ptr, info_ptr); // Allocate the image_data as a big block, to be given to opengl png_byte * image_data; image_data = NEWA(png_byte, rowbytes * temp_height); assert(image_data!=NULL); // row_pointers is for pointing to image_data for reading the png with libpng png_bytep * row_pointers = NEWA(png_bytep, temp_height); assert(row_pointers!=NULL); // set the individual row_pointers to point at the correct offsets of image_data unsigned int i; for (i = 0; i <temp_height; i++) row_pointers[i] = image_data + i * rowbytes; // read the png into image_data through row_pointers png_read_image(png_ptr, row_pointers); // copy into color image color_image_t* image = color_image_new(temp_width,temp_height); if( color_type==0 ) { assert((unsigned)rowbytes == temp_width || !"error: not a proper gray png image"); for(i=0; i<temp_width*temp_height; i++) image->c1[i] = image->c2[i] = image->c3[i] = image_data[i]; } else if( color_type == 2 ) { assert((unsigned)rowbytes == 3*temp_width || !"error: not a proper color png image"); for(i=0; i<temp_width*temp_height; i++) { image->c1[i] = image_data[3*i+0]; image->c2[i] = image_data[3*i+1]; image->c3[i] = image_data[3*i+2]; } } else assert(!"error: unknown PNG color type" ); // clean up png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); free(row_pointers); return image; }
GLubyte* glmReadPNG(const char* filename, GLboolean alpha, int* width_ret, int* height_ret, int* type_ret) { png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int bit_depth, color_type, interlace_type; FILE *fp; unsigned char *buffer; int y, bytes_per_row; int channels; int format; png_bytepp row_pointers; printf("62"); if ((fp = fopen(filename, "rb")) == NULL) { printf("64"); pngerror = ERR_OPEN; 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, (void *)user_error_ptr, user_error_fn, user_warning_fn);*/ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, err_callback, warn_callback); if (png_ptr == NULL) { pngerror = ERR_MEM; fclose(fp); return 0; } /* Allocate/initialize the memory for image information. REQUIRED. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { pngerror = ERR_MEM; fclose(fp); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return 0; } /* 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. */ buffer = NULL; if (setjmp(setjmp_buffer)) { pngerror = ERR_PNGLIB; /* 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 */ if (buffer) free(buffer); return NULL; } /* Set up the input control if you are using standard C streams */ png_init_io(png_ptr, fp); /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). REQUIRED */ png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); /**** Set up the data transformations you want. Note that these are all **** optional. Only call them if you want/need them. Many of the **** transformations only work on specific types of images, and many **** are mutually exclusive. ****/ /* tell libpng to strip 16 bit/color files down to 8 bits/color */ png_set_strip_16(png_ptr); /* strip alpha bytes from the input data without combining with th * background (not recommended) */ /* png_set_strip_alpha(png_ptr); */ /* extract multiple pixels with bit depths of 1, 2, and 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ /* png_set_packing(png_ptr); */ /* change the order of packed pixels to least significant bit first * (not useful if you are using png_set_packing). */ /* png_set_packswap(png_ptr); */ /* expand paletted colors into true RGB triplets */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(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); /* expand paletted or RGB images with transparency to full alpha channels * so the data will be available as RGBA quartets */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); /* Add filler (or alpha) byte (before/after each RGB triplet) */ /* png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); */ png_read_update_info(png_ptr, info_ptr); channels = png_get_channels(png_ptr, info_ptr); /* allocate the memory to hold the image using the fields of info_ptr. */ bytes_per_row = png_get_rowbytes(png_ptr, info_ptr); buffer = (unsigned char*) malloc(bytes_per_row*height); format = channels; row_pointers = (png_bytepp) malloc(height*sizeof(png_bytep)); for (y = 0; y < height; y++) { row_pointers[height-y-1] = buffer + y*bytes_per_row; } png_read_image(png_ptr, row_pointers); png_read_end(png_ptr, info_ptr); free(row_pointers); /* clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); /* close the file */ fclose(fp); /* that's it */ if (buffer) { *width_ret = width; *height_ret = height; switch(format) { case 1: *type_ret = GL_LUMINANCE; break; case 2: *type_ret = GL_LUMINANCE_ALPHA; break; case 3: *type_ret = GL_RGB; break; case 4: *type_ret = GL_RGBA; break; } pngerror = ERR_NO_ERROR; } else { pngerror = ERR_MEM; } return buffer; }
static void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, float screen_gamma=0.0) { if (screen_gamma != 0.0 && png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) { double file_gamma; png_get_gAMA(png_ptr, info_ptr, &file_gamma); png_set_gamma(png_ptr, screen_gamma, file_gamma); } png_uint_32 width; png_uint_32 height; int bit_depth; int color_type; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); if (color_type == PNG_COLOR_TYPE_GRAY) { // Black & White or 8-bit grayscale if (bit_depth == 1 && info_ptr->channels == 1) { png_set_invert_mono(png_ptr); png_read_update_info(png_ptr, info_ptr); if (image.size() != QSize(width, height) || image.format() != QImage::Format_Mono) { image = QImage(width, height, QImage::Format_Mono); if (image.isNull()) return; } image.setNumColors(2); image.setColor(1, qRgb(0,0,0)); image.setColor(0, qRgb(255,255,255)); } else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_expand(png_ptr); png_set_strip_16(png_ptr); png_set_gray_to_rgb(png_ptr); if (image.size() != QSize(width, height) || image.format() != QImage::Format_ARGB32) { image = QImage(width, height, QImage::Format_ARGB32); if (image.isNull()) return; } if (QSysInfo::ByteOrder == QSysInfo::BigEndian) png_set_swap_alpha(png_ptr); png_read_update_info(png_ptr, info_ptr); } else { if (bit_depth == 16) png_set_strip_16(png_ptr); else if (bit_depth < 8) png_set_packing(png_ptr); int ncols = bit_depth < 8 ? 1 << bit_depth : 256; png_read_update_info(png_ptr, info_ptr); if (image.size() != QSize(width, height) || image.format() != QImage::Format_Indexed8) { image = QImage(width, height, QImage::Format_Indexed8); if (image.isNull()) return; } image.setNumColors(ncols); for (int i=0; i<ncols; i++) { int c = i*255/(ncols-1); image.setColor(i, qRgba(c,c,c,0xff)); } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { const int g = info_ptr->trans_values.gray; if (g < ncols) { image.setColor(g, 0); } } } } else if (color_type == PNG_COLOR_TYPE_PALETTE && png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE) && info_ptr->num_palette <= 256) { // 1-bit and 8-bit color if (bit_depth != 1) png_set_packing(png_ptr); png_read_update_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); QImage::Format format = bit_depth == 1 ? QImage::Format_Mono : QImage::Format_Indexed8; if (image.size() != QSize(width, height) || image.format() != format) { image = QImage(width, height, format); if (image.isNull()) return; } image.setNumColors(info_ptr->num_palette); int i = 0; if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { while (i < info_ptr->num_trans) { image.setColor(i, qRgba( info_ptr->palette[i].red, info_ptr->palette[i].green, info_ptr->palette[i].blue, info_ptr->trans[i] ) ); i++; } } while (i < info_ptr->num_palette) { image.setColor(i, qRgba( info_ptr->palette[i].red, info_ptr->palette[i].green, info_ptr->palette[i].blue, 0xff ) ); i++; } } else { // 32-bit if (bit_depth == 16) png_set_strip_16(png_ptr); png_set_expand(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); QImage::Format format = QImage::Format_ARGB32; // Only add filler if no alpha, or we can get 5 channel data. if (!(color_type & PNG_COLOR_MASK_ALPHA) && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_filler(png_ptr, 0xff, QSysInfo::ByteOrder == QSysInfo::BigEndian ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER); // We want 4 bytes, but it isn't an alpha channel format = QImage::Format_RGB32; } if (image.size() != QSize(width, height) || image.format() != format) { image = QImage(width, height, format); if (image.isNull()) return; } if (QSysInfo::ByteOrder == QSysInfo::BigEndian) png_set_swap_alpha(png_ptr); png_read_update_info(png_ptr, info_ptr); } // Qt==ARGB==Big(ARGB)==Little(BGRA) if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) { png_set_bgr(png_ptr); } }
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; png_colorp png_palette; int color_type, palette_entries; int bit_depth, pixel_depth; // pixel_depth = bit_depth * channels FIBITMAP *dib = NULL; RGBQUAD *palette = NULL; // pointer to dib palette png_bytepp row_pointers = NULL; int i; fi_ioStructure fio; fio.s_handle = handle; fio.s_io = io; if (handle) { try { // check to see if the file is in fact a PNG file unsigned char png_check[PNG_BYTES_TO_CHECK]; io->read_proc(png_check, PNG_BYTES_TO_CHECK, 1, handle); if (png_sig_cmp(png_check, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) return NULL; // Bad signature // create the chunk manage structure png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler); if (!png_ptr) return NULL; // create the info structure info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return NULL; } // init the IO png_set_read_fn(png_ptr, &fio, _ReadProc); if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } // because we have already read the signature... png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); // read the IHDR chunk png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); pixel_depth = info_ptr->pixel_depth; // get image data type (assume standard image type) FREE_IMAGE_TYPE image_type = FIT_BITMAP; if (bit_depth == 16) { if ((pixel_depth == 16) && (color_type == PNG_COLOR_TYPE_GRAY)) { image_type = FIT_UINT16; #ifndef FREEIMAGE_BIGENDIAN // turn on 16 bit byte swapping png_set_swap(png_ptr); #endif } else if ((pixel_depth == 48) && (color_type == PNG_COLOR_TYPE_RGB)) { image_type = FIT_RGB16; #ifndef FREEIMAGE_BIGENDIAN // turn on 16 bit byte swapping png_set_swap(png_ptr); #endif } else { // tell libpng to strip 16 bit/color files down to 8 bits/color png_set_strip_16(png_ptr); bit_depth = 8; } } // set some additional flags switch(color_type) { case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: #ifndef FREEIMAGE_BIGENDIAN // flip the RGB pixels to BGR (or RGBA to BGRA) if(image_type == FIT_BITMAP) png_set_bgr(png_ptr); #endif break; case PNG_COLOR_TYPE_PALETTE: // expand palette images to the full 8 bits from 2 bits/pixel if (pixel_depth == 2) { png_set_packing(png_ptr); pixel_depth = 8; } break; case PNG_COLOR_TYPE_GRAY: // expand grayscale images to the full 8 bits from 2 bits/pixel if (pixel_depth == 2) { png_set_expand(png_ptr); pixel_depth = 8; } break; case PNG_COLOR_TYPE_GRAY_ALPHA: // expand 8-bit greyscale + 8-bit alpha to 32-bit png_set_gray_to_rgb(png_ptr); #ifndef FREEIMAGE_BIGENDIAN // flip the RGBA pixels to BGRA png_set_bgr(png_ptr); #endif pixel_depth = 32; break; default: throw "PNG format not supported"; } // Get the background color to draw transparent and alpha images over. // Note that even if the PNG file supplies a background, you are not required to // use it - you should use the (solid) application background if it has one. png_color_16p image_background = NULL; RGBQUAD rgbBkColor; if (png_get_bKGD(png_ptr, info_ptr, &image_background)) { rgbBkColor.rgbRed = (BYTE)image_background->red; rgbBkColor.rgbGreen = (BYTE)image_background->green; rgbBkColor.rgbBlue = (BYTE)image_background->blue; rgbBkColor.rgbReserved = 0; } // if this image has transparency, store the trns values png_bytep trans = NULL; int num_trans = 0; png_color_16p trans_values = NULL; png_uint_32 transparent_value = png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values); // 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") 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); // color type may have changed, due to our transformations color_type = png_get_color_type(png_ptr,info_ptr); // create a DIB and write the bitmap header // set up the DIB palette, if needed switch (color_type) { case PNG_COLOR_TYPE_RGB: png_set_invert_alpha(png_ptr); if(image_type == FIT_BITMAP) { dib = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } else { dib = FreeImage_AllocateT(image_type, width, height, pixel_depth); } break; case PNG_COLOR_TYPE_RGB_ALPHA : dib = FreeImage_Allocate(width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); break; case PNG_COLOR_TYPE_PALETTE : dib = FreeImage_Allocate(width, height, pixel_depth); png_get_PLTE(png_ptr,info_ptr, &png_palette,&palette_entries); palette = FreeImage_GetPalette(dib); // store the palette for (i = 0; i < palette_entries; i++) { palette[i].rgbRed = png_palette[i].red; palette[i].rgbGreen = png_palette[i].green; palette[i].rgbBlue = png_palette[i].blue; } // store the transparency table if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) FreeImage_SetTransparencyTable(dib, (BYTE *)trans, num_trans); break; case PNG_COLOR_TYPE_GRAY: dib = FreeImage_AllocateT(image_type, width, height, pixel_depth); if(pixel_depth <= 8) { palette = FreeImage_GetPalette(dib); palette_entries = 1 << pixel_depth; for (i = 0; i < palette_entries; i++) { palette[i].rgbRed = palette[i].rgbGreen = palette[i].rgbBlue = (i * 255) / (palette_entries - 1); } } // store the transparency table if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) FreeImage_SetTransparencyTable(dib, (BYTE *)trans, num_trans); break; default: throw "PNG format not supported"; } // store the background color if(image_background) { FreeImage_SetBackgroundColor(dib, &rgbBkColor); } // get physical resolution if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) { png_uint_32 res_x, res_y; // we'll overload this var and use 0 to mean no phys data, // since if it's not in meters we can't use it anyway int res_unit_type = 0; png_get_pHYs(png_ptr,info_ptr,&res_x,&res_y,&res_unit_type); if (res_unit_type == 1) { BITMAPINFOHEADER *bih = FreeImage_GetInfoHeader(dib); bih->biXPelsPerMeter = res_x; bih->biYPelsPerMeter = res_y; } } // get possible ICC profile if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) { png_charp profile_name = NULL; png_charp profile_data = NULL; png_uint_32 profile_length = 0; int compression_type; png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &profile_length); // copy ICC profile data (must be done after FreeImage_Allocate) FreeImage_CreateICCProfile(dib, profile_data, profile_length); } // set the individual row_pointers to point at the correct offsets row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep)); if (!row_pointers) { if (palette) png_free(png_ptr, palette); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); FreeImage_Unload(dib); return NULL; } // read in the bitmap bits via the pointer table for (png_uint_32 k = 0; k < height; k++) row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k); png_read_image(png_ptr, row_pointers); // check if the bitmap contains transparency, if so enable it in the header if (FreeImage_GetBPP(dib) == 32) if (FreeImage_GetColorType(dib) == FIC_RGBALPHA) FreeImage_SetTransparent(dib, TRUE); else FreeImage_SetTransparent(dib, FALSE); // cleanup if (row_pointers) { free(row_pointers); row_pointers = NULL; } // read the rest of the file, getting any additional chunks in info_ptr png_read_end(png_ptr, info_ptr); // get possible metadata (it can be located both before and after the image data) ReadMetadata(png_ptr, info_ptr, dib); if (png_ptr) { // clean up after the read, and free any memory allocated - REQUIRED png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } return dib; } catch (const char *text) { if (png_ptr) png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); if (row_pointers) free(row_pointers); if (dib) FreeImage_Unload(dib); FreeImage_OutputMessageProc(s_format_id, text); return NULL; } } return NULL; }
void LoadPNG (char *filename, byte **pic, int *width, int *height) { png_structp png; png_infop pnginfo; byte ioBuffer[8192]; int len; byte *raw; *pic=0; len = ri.FS_LoadFile (filename, (void **)&raw); if (!raw) { ri.Con_Printf (PRINT_DEVELOPER, "Bad png file %s\n", filename); return; } if( png_sig_cmp(raw,0,4)) return; png = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0); if(!png) return; pnginfo = png_create_info_struct( png ); if(!pnginfo) { 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 = 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_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 ); 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); //only load 32 bit by now... if (my_png->BitDepth == 8) { *pic= my_png->Data; *width = my_png->Width; *height = my_png->Height; } else { ri.Con_Printf (PRINT_DEVELOPER, "Bad png color depth: %s\n", filename); *pic = NULL; free(my_png->Data); } mypng_struct_destroy(true); ri.FS_FreeFile ((void *)raw); }
static e_texture_t* e_loadpng(e_device_t* device,int mipmaps,fs_handle_t file) { unsigned int width,height; unsigned int rowbytes; unsigned char* data; unsigned char** rows; unsigned int i; int bpp,type; int format; png_structp png; png_infop info; e_texture_t* texture; if(!e_checkpng(file)) return 0; png=png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,(png_error_ptr)0,(png_error_ptr)0); if(!png) return 0; info=png_create_info_struct(png); if(!info) { png_destroy_read_struct(&png,0,0); return 0; } //Needed by libpng if(setjmp(png_jmpbuf(png))) { png_destroy_read_struct(&png,&info,0); if(rows) sys_free(rows); if(data) sys_free(data); return 0; } //Read up to image data png_set_read_fn(png,(png_voidp)file,e_readpng); png_set_sig_bytes(png,8); png_read_info(png,info); png_get_IHDR(png,info,&width,&height,&bpp,&type,0,0,0); if(width!=e_pow2(width)|| height!=e_pow2(height)) longjmp(png_jmpbuf(png),1); //Convert this image to fit the required format if(type==PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); if(type==PNG_COLOR_TYPE_GRAY|| type==PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); if(type==PNG_COLOR_TYPE_GRAY||bpp<8) png_set_expand(png); if(png_get_valid(png,info,PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); png_read_update_info(png,info); rowbytes=png_get_rowbytes(png,info); //Allocate memory to store the image data=(unsigned char*)sys_alloc(rowbytes*height); if(!data) longjmp(png_jmpbuf(png),1); rows=(unsigned char**)sys_alloc(sizeof(unsigned char*)*height); if(!rows) longjmp(png_jmpbuf(png),1); for(i=0;i<height;i++) rows[i]=data+(height-(i+1))*rowbytes; //Read png png_read_image(png,rows); png_read_end(png,0); sys_free(rows); texture=(e_texture_t*)sys_alloc(sizeof(e_texture_t)); texture->width=width; texture->height=height; glGenTextures(1,&texture->id); glBindTexture(GL_TEXTURE_2D,texture->id); texture->bpp=(type&PNG_COLOR_MASK_ALPHA)?32:24; format=(type&PNG_COLOR_MASK_ALPHA)?GL_RGBA:GL_RGB; glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); if(mipmaps) gluBuild2DMipmaps(GL_TEXTURE_2D,(type&PNG_COLOR_MASK_ALPHA)?4:3,texture->width,texture->height,format,GL_UNSIGNED_BYTE,data); else glTexImage2D(GL_TEXTURE_2D,0,format,texture->width,texture->height,0,format,GL_UNSIGNED_BYTE,data); sys_free(data); return texture; }
void PNGAPI png_read_png(png_structp png_ptr, png_infop info_ptr, int transforms, voidp params) { int row; if (png_ptr == NULL) return; #if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) /* invert the alpha channel from opacity to transparency */ if (transforms & PNG_TRANSFORM_INVERT_ALPHA) png_set_invert_alpha(png_ptr); #endif /* 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); if (info_ptr->height > PNG_UINT_32_MAX/png_sizeof(png_bytep)) png_error(png_ptr, "Image is too high to process with png_read_png()"); /* -------------- image transformations start here ------------------- */ #if defined(PNG_READ_16_TO_8_SUPPORTED) /* tell libpng to strip 16 bit/color files down to 8 bits per color */ if (transforms & PNG_TRANSFORM_STRIP_16) png_set_strip_16(png_ptr); #endif #if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) /* Strip alpha bytes from the input data without combining with * the background (not recommended). */ if (transforms & PNG_TRANSFORM_STRIP_ALPHA) png_set_strip_alpha(png_ptr); #endif #if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED) /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ if (transforms & PNG_TRANSFORM_PACKING) png_set_packing(png_ptr); #endif #if defined(PNG_READ_PACKSWAP_SUPPORTED) /* Change the order of packed pixels to least significant bit first * (not useful if you are using png_set_packing). */ if (transforms & PNG_TRANSFORM_PACKSWAP) png_set_packswap(png_ptr); #endif #if defined(PNG_READ_EXPAND_SUPPORTED) /* Expand paletted colors into true RGB triplets * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel * Expand paletted or RGB images with transparency to full alpha * channels so the data will be available as RGBA quartets. */ if (transforms & PNG_TRANSFORM_EXPAND) if ((png_ptr->bit_depth < 8) || (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) || (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))) png_set_expand(png_ptr); #endif /* We don't handle background color or gamma transformation or dithering. */ #if defined(PNG_READ_INVERT_SUPPORTED) /* invert monochrome files to have 0 as white and 1 as black */ if (transforms & PNG_TRANSFORM_INVERT_MONO) png_set_invert_mono(png_ptr); #endif #if defined(PNG_READ_SHIFT_SUPPORTED) /* If you want to shift the pixel values from the range [0,255] or * [0,65535] to the original [0,7] or [0,31], or whatever range the * colors were originally in: */ if ((transforms & PNG_TRANSFORM_SHIFT) && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) { png_color_8p sig_bit; png_get_sBIT(png_ptr, info_ptr, &sig_bit); png_set_shift(png_ptr, sig_bit); } #endif #if defined(PNG_READ_BGR_SUPPORTED) /* flip the RGB pixels to BGR (or RGBA to BGRA) */ if (transforms & PNG_TRANSFORM_BGR) png_set_bgr(png_ptr); #endif #if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ if (transforms & PNG_TRANSFORM_SWAP_ALPHA) png_set_swap_alpha(png_ptr); #endif #if defined(PNG_READ_SWAP_SUPPORTED) /* swap bytes of 16 bit files to least significant byte first */ if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) png_set_swap(png_ptr); #endif /* We don't handle adding filler bytes */ /* Optional call to gamma correct and add the background to the palette * and update info structure. REQUIRED if you are expecting libpng to * update the palette for you (i.e., you selected such a transform above). */ png_read_update_info(png_ptr, info_ptr); /* -------------- image transformations end here ------------------- */ #ifdef PNG_FREE_ME_SUPPORTED png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); #endif if (info_ptr->row_pointers == NULL) { info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr, info_ptr->height * png_sizeof(png_bytep)); #ifdef PNG_FREE_ME_SUPPORTED info_ptr->free_me |= PNG_FREE_ROWS; #endif png_memset(info_ptr->row_pointers, 0, info_ptr->height * png_sizeof(png_bytep)); for (row = 0; row < (int)info_ptr->height; row++) info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); } png_read_image(png_ptr, info_ptr->row_pointers); info_ptr->valid |= PNG_INFO_IDAT; /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); transforms = transforms; /* quiet compiler warnings */ params = params; }
void png_load_from_memory(aasset_buffer_t& buf, raw_bitmap_t* out_bitmap) { //png header - 8 bytes if (png_sig_cmp(buf.data(), 0, 8)) { my_assert(false && "Couldn't load texture. It isn't png file."); return; } auto png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); my_assert(png_ptr && "Couldn't load texture. Png load error."); MAKE_GUARD(png_ptr, [](decltype(png_ptr) ptr) { png_destroy_read_struct(&ptr, (png_infopp)NULL, (png_infopp)NULL);}); auto info_ptr = png_create_info_struct(png_ptr); my_assert(info_ptr && "Couldn't load texture. Png load error."); auto info_deleter = [png_ptr](decltype(info_ptr) ptr) { png_destroy_info_struct(png_ptr, &ptr);}; MAKE_GUARD(info_ptr, info_deleter); // the code in this if statement gets called if libpng encounters an error if (setjmp((long*) png_jmpbuf(png_ptr))) { my_assert(false && "error from libpng"); return; } png_set_read_fn(png_ptr, &buf, read_from_aasset_buffer); // tell libpng we already read the signature png_set_sig_bytes(png_ptr, 8); buf.seek(8); png_read_info(png_ptr, info_ptr); png_uint_32 width = 0; png_uint_32 height = 0; int bitDepth = 0; int colorType = -1; auto res = png_get_IHDR(png_ptr, info_ptr, &width, &height, &bitDepth, &colorType, NULL, NULL, NULL); my_assert(res == 1); bool transparency = false; if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); transparency = true; } // Expands PNG with less than 8bits per channel to 8bits. if (bitDepth < 8) { png_set_packing(png_ptr); // Shrinks PNG with 16bits per color channel down to 8bits. } else if (bitDepth == 16) { png_set_strip_16(png_ptr); } uint32_t format = 0; switch (colorType) { case PNG_COLOR_TYPE_RGB: format = transparency ? GL_RGBA : GL_RGB; break; case PNG_COLOR_TYPE_RGBA: format = GL_RGBA; break; case PNG_COLOR_TYPE_PALETTE: { png_set_palette_to_rgb(png_ptr); format = transparency ? GL_RGBA : GL_RGB; break; } default: my_assert(false && "Png read error. Uknown color type"); return; } //apply transformations png_read_update_info(png_ptr, info_ptr); out_bitmap->init(width, height, format); auto row_size = png_get_rowbytes(png_ptr, info_ptr); my_assert(row_size > 0); my_assert(row_size == width * out_bitmap->bytes_per_pixel()); auto row_ptrs = new png_bytep[height]; MAKE_GUARD(row_ptrs, [](decltype(row_ptrs) ptr) { delete[] ptr;}); for (int32_t i = 0; i < height; ++i) { row_ptrs[height - (i + 1)] = out_bitmap->get_row(i); } png_read_image(png_ptr, row_ptrs); }
Error ImageLoaderPNG::_load_image(void *rf_up,png_rw_ptr p_func,Image *p_image) { png_structp png; png_infop info; //png = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL); png = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,_png_error_function,_png_warn_function,(png_voidp)NULL, _png_malloc_fn,_png_free_fn ); ERR_FAIL_COND_V(!png, ERR_OUT_OF_MEMORY); info = png_create_info_struct(png); if (!info) { png_destroy_read_struct(&png,NULL,NULL); ERR_PRINT("Out of Memory"); return ERR_OUT_OF_MEMORY; } if (setjmp(png_jmpbuf(png))) { png_destroy_read_struct(&png,NULL,NULL); ERR_PRINT("PNG Corrupted"); return ERR_FILE_CORRUPT; } png_set_read_fn(png,(void*)rf_up,p_func); png_uint_32 width, height; int depth, color; png_read_info(png, info); png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL); //https://svn.gov.pt/projects/ccidadao/repository/middleware-offline/trunk/_src/eidmw/FreeImagePTEiD/Source/FreeImage/PluginPNG.cpp //png_get_text(png,info,) /* printf("Image width:%i\n", width); printf("Image Height:%i\n", height); printf("Bit depth:%i\n", depth); printf("Color type:%i\n", color); */ if (depth<8) { //only bit dept 8 per channel is handled png_set_packing(png); }; if (depth > 8) { png_set_strip_16(png); png_read_update_info(png, info); } if (png_get_valid(png,info,PNG_INFO_tRNS)) { // png_set_expand_gray_1_2_4_to_8(png); png_set_tRNS_to_alpha(png); png_read_update_info(png, info); png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL); } int palette_colors = 0; int palette_components = 0; int components = 0; Image::Format fmt; switch(color) { case PNG_COLOR_TYPE_GRAY: { fmt=Image::FORMAT_GRAYSCALE; components=1; } break; case PNG_COLOR_TYPE_GRAY_ALPHA: { fmt=Image::FORMAT_GRAYSCALE_ALPHA; components=2; } break; case PNG_COLOR_TYPE_RGB: { fmt=Image::FORMAT_RGB; components=3; } break; case PNG_COLOR_TYPE_RGB_ALPHA: { fmt=Image::FORMAT_RGBA; components=4; } break; case PNG_COLOR_TYPE_PALETTE: { int ntrans = 0; png_get_tRNS(png, info, NULL, &ntrans, NULL); //printf("transparent colors %i\n", ntrans); fmt = ntrans > 0 ? Image::FORMAT_INDEXED_ALPHA : Image::FORMAT_INDEXED; palette_components = ntrans > 0 ? 4 : 3; components = 1; png_colorp colors; png_get_PLTE(png, info, &colors, &palette_colors); } break; default: { ERR_PRINT("INVALID PNG TYPE"); png_destroy_read_struct(&png, &info, NULL); return ERR_UNAVAILABLE; } break; } //int rowsize = png_get_rowbytes(png, info); int rowsize = components * width; DVector<uint8_t> dstbuff; dstbuff.resize( rowsize * height + palette_components * 256 ); // alloc the entire palette? - yes always DVector<uint8_t>::Write dstbuff_write = dstbuff.write(); uint8_t* data = dstbuff_write.ptr(); uint8_t **row_p = memnew_arr( uint8_t*, height ); for (unsigned int i = 0; i < height; i++) { row_p[i] = &data[components*width*i]; } png_read_image(png, (png_bytep*)row_p); if (palette_colors) { uint8_t *r_pal = &data[components*width*height]; // end of the array png_colorp colors; int num; png_get_PLTE(png, info, &colors, &num); int ofs = 0; for (int i=0; i < palette_colors; i++) { r_pal[ofs + 0] = colors[i].red; r_pal[ofs + 1] = colors[i].green; r_pal[ofs + 2] = colors[i].blue; if (palette_components == 4) { r_pal[ofs + 3] = 255; }; ofs += palette_components; }; if (fmt == Image::FORMAT_INDEXED_ALPHA) { png_color_16p alphas; png_bytep alpha_idx; int count; png_get_tRNS(png, info, &alpha_idx, &count, &alphas); for (int i=0; i<count; i++) { //printf("%i: loading alpha fron transparent color %i, values %i, %i, %i, %i, %i\n", i, (int)alpha_idx[i], (int)alphas[i].index, (int)alphas[i].red, (int)alphas[i].green, (int)alphas[i].blue, (int)alphas[i].gray); //r_pal[alpha_idx[i]] = alphas[i].gray >> 8; r_pal[i*4+3] = alpha_idx[i]; }; }; }; memdelete_arr( row_p ); p_image->create( width, height, 0,fmt, dstbuff ); png_destroy_read_struct(&png, &info, NULL ); return OK; }
ImageNode *LoadPNGImage(const char *fileName) { static ImageNode *result; static FILE *fd; static unsigned char **rows; static png_structp pngData; static png_infop pngInfo; static png_infop pngEndInfo; unsigned char header[8]; unsigned long rowBytes; int bitDepth, colorType; unsigned int x, y; png_uint_32 width; png_uint_32 height; Assert(fileName); result = NULL; fd = NULL; rows = NULL; pngData = NULL; pngInfo = NULL; pngEndInfo = NULL; fd = fopen(fileName, "rb"); if(!fd) { return NULL; } x = fread(header, 1, sizeof(header), fd); if(x != sizeof(header) || png_sig_cmp(header, 0, sizeof(header))) { fclose(fd); return NULL; } pngData = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(JUNLIKELY(!pngData)) { fclose(fd); Warning(_("could not create read struct for PNG image: %s"), fileName); return NULL; } if(JUNLIKELY(setjmp(png_jmpbuf(pngData)))) { png_destroy_read_struct(&pngData, &pngInfo, &pngEndInfo); if(fd) { fclose(fd); } if(rows) { ReleaseStack(rows); } DestroyImage(result); Warning(_("error reading PNG image: %s"), fileName); return NULL; } pngInfo = png_create_info_struct(pngData); if(JUNLIKELY(!pngInfo)) { png_destroy_read_struct(&pngData, NULL, NULL); fclose(fd); Warning(_("could not create info struct for PNG image: %s"), fileName); return NULL; } pngEndInfo = png_create_info_struct(pngData); if(JUNLIKELY(!pngEndInfo)) { png_destroy_read_struct(&pngData, &pngInfo, NULL); fclose(fd); Warning("could not create end info struct for PNG image: %s", fileName); return NULL; } png_init_io(pngData, fd); png_set_sig_bytes(pngData, sizeof(header)); png_read_info(pngData, pngInfo); png_get_IHDR(pngData, pngInfo, &width, &height, &bitDepth, &colorType, NULL, NULL, NULL); result = CreateImage(width, height, 0); png_set_expand(pngData); if(bitDepth == 16) { png_set_strip_16(pngData); } else if(bitDepth < 8) { png_set_packing(pngData); } png_set_swap_alpha(pngData); png_set_filler(pngData, 0xFF, PNG_FILLER_BEFORE); if(colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(pngData); } png_read_update_info(pngData, pngInfo); rowBytes = png_get_rowbytes(pngData, pngInfo); rows = AllocateStack(result->height * sizeof(result->data)); y = 0; for(x = 0; x < result->height; x++) { rows[x] = &result->data[y]; y += rowBytes; } png_read_image(pngData, rows); png_read_end(pngData, pngInfo); png_destroy_read_struct(&pngData, &pngInfo, &pngEndInfo); fclose(fd); ReleaseStack(rows); rows = NULL; return result; }
void loadNativePNG(texture_t* tmpTex) { png_structp png_ptr; png_infop info_ptr; unsigned int width; unsigned int height; int i; int bit_depth; int color_type ; png_size_t rowbytes; png_bytep *row_pointers; png_byte header[8]; char realPath[1024]; memset(realPath, 0, 1024); strcat(realPath, FS_Gamedir()); if (tmpTex->path[0] != '/') strcat(realPath, "/"); strcat(realPath, tmpTex->path); tmpTex->format = TEXTURE_TYPE_UNKNOWN ; file = zip_fopen(APKArchive, realPath, 0); //LOGI("[Android Main] Opening %s", realPath); if ( !file ) abort_textureLoading_("Could not open file '%s'\n",tmpTex->path); zip_fread(file, header, 8); if (png_sig_cmp(header, 0, 8) != 0 ) abort_textureLoading_("[read_png_file] File is not recognized as a PNG file.\n", tmpTex->path); // initialize png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) abort_textureLoading_("[read_png_file] png_create_read_struct failed"); info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) abort_textureLoading_("[read_png_file] png_create_info_struct failed"); if (setjmp(png_jmpbuf(png_ptr))) abort_textureLoading_("[read_png_file] Error during init_io"); png_set_read_fn(png_ptr, NULL, png_zip_read); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); //Retrieve metadata and transfer to structure bean tmpTex png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); tmpTex->width = width; tmpTex->height = height; // Set up some transforms. /*if (color_type & PNG_COLOR_MASK_ALPHA) { png_set_strip_alpha(png_ptr); }*/ if (bit_depth > 8) { 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); } if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } // Update the png info struct. png_read_update_info(png_ptr, info_ptr); // Rowsize in bytes. rowbytes = png_get_rowbytes(png_ptr, info_ptr); tmpTex->bpp = rowbytes / width; if (tmpTex->bpp == 4) tmpTex->format = TEXTURE_GL_RGBA; else tmpTex->format = TEXTURE_GL_RGB; LOGI("DEBUG: For %s, bpp: %i, color_type: %i, bit_depth: %i", realPath, tmpTex->bpp, color_type, bit_depth); //Since PNG can only store one image there is only one mipmap, allocated an array of one tmpTex->numMipmaps = 1; tmpTex->data = malloc(sizeof(uchar*)); if ((tmpTex->data[0] = (uchar*)malloc(rowbytes * height))==NULL) { //Oops texture won't be able to hold the result :(, cleanup LIBPNG internal state and return; free(tmpTex->data); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return; } //Next we need to send to libpng an array of pointer, let's point to tmpTex->data[0] if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) { // Oops looks like we won't have enough RAM to allocate an array of pointer.... png_destroy_read_struct(&png_ptr, &info_ptr, NULL); free(tmpTex->data ); tmpTex->data = NULL; return; } //FCS: Hm, it looks like we are flipping the image vertically. // Since iOS did not do it, we may have to not to that. If result is // messed up, just swap to: row_pointers[ i] = .... for (i = 0; i < height; ++i) //row_pointers[height - 1 - i] = tmpTex->data[0] + i * rowbytes; row_pointers[ i] = tmpTex->data[0] + i*rowbytes; //Decompressing PNG to RAW where row_pointers are pointing (tmpTex->data[0]) png_read_image(png_ptr, row_pointers); //Last but not least: // Free LIBPNG internal state. png_destroy_read_struct(&png_ptr, &info_ptr, NULL); //Free the decompression buffer free(row_pointers); zip_fclose(file); }
GLuint png_texture_load(const char * file_name, int width, int height) { png_uint_32 temp_width, temp_height; int bit_depth, color_type, i; png_byte header[8]; GLuint texture; FILE *fp = fopen(file_name, "rb"); if (fp == 0) { perror(file_name); return 0; } // read the header fread(header, 1, 8, fp); if (png_sig_cmp(header, 0, 8)) { fprintf(stderr, "error: %s is not a PNG.\n", file_name); fclose(fp); return 0; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fprintf(stderr, "error: png_create_read_struct returned 0.\n"); fclose(fp); return 0; } // create png info struct info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { fprintf(stderr, "error: png_create_info_struct returned 0.\n"); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); fclose(fp); return 0; } // create png info struct end_info = png_create_info_struct(png_ptr); if (!end_info) { fprintf(stderr, "error: png_create_info_struct returned 0.\n"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); fclose(fp); return 0; } // the code in this if statement gets called if libpng encounters an error if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr, "error from libpng\n"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return 0; } // init png reading png_init_io(png_ptr, fp); // let libpng know you already read the first 8 bytes png_set_sig_bytes(png_ptr, 8); // read all the info up to the image data png_read_info(png_ptr, info_ptr); // variables to pass to get info // get info about png png_get_IHDR(png_ptr, info_ptr, &temp_width, &temp_height, &bit_depth, &color_type, NULL, NULL, NULL); #if 0 if (width ) { width = temp_width; } if (height ) { height = temp_height; } #endif // Update the png info struct. png_read_update_info(png_ptr, info_ptr); // Row size in bytes. rowbytes = png_get_rowbytes(png_ptr, info_ptr); // glTexImage2d requires rows to be 4-byte aligned rowbytes += 3 - ((rowbytes-1) % 4); // Allocate the image_data as a big block, to be given to opengl image_data = (png_byte*)malloc(rowbytes * temp_height * sizeof(png_byte)+15); if (image_data == NULL) { fprintf(stderr, "error: could not allocate memory for PNG image data\n"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return 0; } // row_pointers is for pointing to image_data for reading the png with libpng row_pointers = (png_bytep*)malloc(temp_height * sizeof(png_bytep)); if (row_pointers == NULL) { fprintf(stderr, "error: could not allocate memory for PNG row pointers\n"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); free(image_data); fclose(fp); return 0; } // set the individual row_pointers to point at the correct offsets of image_data for (i = 0; i < temp_height; i++) { row_pointers[temp_height - 1 - i] = image_data + i * rowbytes; } // read the png into image_data through row_pointers png_read_image(png_ptr, row_pointers); // Generate the OpenGL texture object glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, temp_width, temp_height, 0, GL_RGB, GL_UNSIGNED_BYTE, image_data); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // clean up png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); free(image_data); free(row_pointers); fclose(fp); return texture; }
int png_include_image (pdf_ximage *ximage, FILE *png_file) { pdf_obj *stream; pdf_obj *stream_dict; pdf_obj *colorspace, *mask, *intent; png_bytep stream_data_ptr; int trans_type; ximage_info info; /* Libpng stuff */ png_structp png_ptr; png_infop png_info_ptr; png_byte bpc, color_type; png_uint_32 width, height, rowbytes; pdf_ximage_init_image_info(&info); stream = NULL; stream_dict = NULL; colorspace = mask = intent = NULL; rewind (png_file); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, warn); if (png_ptr == NULL || (png_info_ptr = png_create_info_struct (png_ptr)) == NULL) { WARN("%s: Creating Libpng read/info struct failed.", PNG_DEBUG_STR); if (png_ptr) png_destroy_read_struct(&png_ptr, NULL, NULL); return -1; } #if PNG_LIBPNG_VER >= 10603 /* ignore possibly incorrect CMF bytes */ png_set_option(png_ptr, PNG_MAXIMUM_INFLATE_WINDOW, PNG_OPTION_ON); #endif /* Inititializing file IO. */ png_init_io (png_ptr, png_file); /* Read PNG info-header and get some info. */ png_read_info(png_ptr, png_info_ptr); color_type = png_get_color_type (png_ptr, png_info_ptr); width = png_get_image_width (png_ptr, png_info_ptr); height = png_get_image_height(png_ptr, png_info_ptr); bpc = png_get_bit_depth (png_ptr, png_info_ptr); /* We do not need 16-bpc color. Ask libpng to convert down to 8-bpc. */ if (bpc > 8) { png_set_strip_16(png_ptr); bpc = 8; } /* Ask libpng to gamma-correct. * It is wrong to assume screen gamma value 2.2 but... * We do gamma correction here only when uncalibrated color space is used. */ if (!png_get_valid(png_ptr, png_info_ptr, PNG_INFO_iCCP) && !png_get_valid(png_ptr, png_info_ptr, PNG_INFO_sRGB) && !png_get_valid(png_ptr, png_info_ptr, PNG_INFO_cHRM) && !png_get_valid(png_ptr, png_info_ptr, PNG_INFO_sRGB) && png_get_valid(png_ptr, png_info_ptr, PNG_INFO_gAMA)) { double G = 1.0; png_get_gAMA (png_ptr, png_info_ptr, &G); png_set_gamma(png_ptr, 2.2, G); } trans_type = check_transparency(png_ptr, png_info_ptr); /* check_transparency() does not do updata_info() */ png_read_update_info(png_ptr, png_info_ptr); rowbytes = png_get_rowbytes(png_ptr, png_info_ptr); /* Values listed below will not be modified in the remaining process. */ info.width = width; info.height = height; info.bits_per_component = bpc; if (compat_mode) info.xdensity = info.ydensity = 72.0 / 100.0; else { png_uint_32 xppm = png_get_x_pixels_per_meter(png_ptr, png_info_ptr); png_uint_32 yppm = png_get_y_pixels_per_meter(png_ptr, png_info_ptr); if (xppm > 0) info.xdensity = 72.0 / 0.0254 / xppm; if (yppm > 0) info.ydensity = 72.0 / 0.0254 / yppm; } stream = pdf_new_stream (STREAM_COMPRESS); stream_dict = pdf_stream_dict(stream); stream_data_ptr = (png_bytep) NEW(rowbytes*height, png_byte); read_image_data(png_ptr, stream_data_ptr, height, rowbytes); /* Non-NULL intent means there is valid sRGB chunk. */ intent = get_rendering_intent(png_ptr, png_info_ptr); if (intent) pdf_add_dict(stream_dict, pdf_new_name("Intent"), intent); switch (color_type) { case PNG_COLOR_TYPE_PALETTE: colorspace = create_cspace_Indexed(png_ptr, png_info_ptr); switch (trans_type) { case PDF_TRANS_TYPE_BINARY: /* Color-key masking */ mask = create_ckey_mask(png_ptr, png_info_ptr); break; case PDF_TRANS_TYPE_ALPHA: /* Soft mask */ mask = create_soft_mask(png_ptr, png_info_ptr, stream_data_ptr, width, height); break; default: /* Nothing to be done here. * No tRNS chunk or image already composited with background color. */ break; } break; case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_iCCP)) colorspace = create_cspace_ICCBased(png_ptr, png_info_ptr); else if (intent) { colorspace = create_cspace_sRGB(png_ptr, png_info_ptr); } else { colorspace = create_cspace_CalRGB(png_ptr, png_info_ptr); } if (!colorspace) colorspace = pdf_new_name("DeviceRGB"); switch (trans_type) { case PDF_TRANS_TYPE_BINARY: mask = create_ckey_mask(png_ptr, png_info_ptr); break; /* rowbytes changes 4 to 3 at here */ case PDF_TRANS_TYPE_ALPHA: mask = strip_soft_mask(png_ptr, png_info_ptr, stream_data_ptr, &rowbytes, width, height); break; default: mask = NULL; } info.num_components = 3; break; case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_GRAY_ALPHA: if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_iCCP)) colorspace = create_cspace_ICCBased(png_ptr, png_info_ptr); else if (intent) { colorspace = create_cspace_sRGB(png_ptr, png_info_ptr); } else { colorspace = create_cspace_CalGray(png_ptr, png_info_ptr); } if (!colorspace) colorspace = pdf_new_name("DeviceGray"); switch (trans_type) { case PDF_TRANS_TYPE_BINARY: mask = create_ckey_mask(png_ptr, png_info_ptr); break; case PDF_TRANS_TYPE_ALPHA: mask = strip_soft_mask(png_ptr, png_info_ptr, stream_data_ptr, &rowbytes, width, height); break; default: mask = NULL; } info.num_components = 1; break; default: WARN("%s: Unknown PNG colortype %d.", PNG_DEBUG_STR, color_type); } pdf_add_dict(stream_dict, pdf_new_name("ColorSpace"), colorspace); pdf_add_stream(stream, stream_data_ptr, rowbytes*height); RELEASE(stream_data_ptr); if (mask) { if (trans_type == PDF_TRANS_TYPE_BINARY) pdf_add_dict(stream_dict, pdf_new_name("Mask"), mask); else if (trans_type == PDF_TRANS_TYPE_ALPHA) { pdf_add_dict(stream_dict, pdf_new_name("SMask"), pdf_ref_obj(mask)); pdf_release_obj(mask); } else { WARN("%s: Unknown transparency type...???", PNG_DEBUG_STR); pdf_release_obj(mask); } } /* Finally read XMP Metadata * See, XMP Specification Part 3, Storage in Files * http://www.adobe.com/jp/devnet/xmp.html * * We require libpng version >= 1.6.14 since prior versions * of libpng had a bug that incorrectly treat the compression * flag of iTxt chunks. */ #if PNG_LIBPNG_VER >= 10614 if (pdf_get_version() >= 4) { png_textp text_ptr; pdf_obj *XMP_stream, *XMP_stream_dict; int i, num_text; int have_XMP = 0; num_text = png_get_text(png_ptr, png_info_ptr, &text_ptr, NULL); for (i = 0; i < num_text; i++) { if (!memcmp(text_ptr[i].key, "XML:com.adobe.xmp", 17)) { /* XMP found */ if (text_ptr[i].compression != PNG_ITXT_COMPRESSION_NONE || text_ptr[i].itxt_length == 0) WARN("%s: Invalid value(s) in iTXt chunk for XMP Metadata.", PNG_DEBUG_STR); else if (have_XMP) WARN("%s: Multiple XMP Metadata. Don't know how to treat it.", PNG_DEBUG_STR); else { /* We compress XMP metadata for included images here. * It is not recommended to compress XMP metadata for PDF documents but * we compress XMP metadata for included images here to avoid confusing * application programs that only want PDF document global XMP metadata * and scan for that. */ XMP_stream = pdf_new_stream(STREAM_COMPRESS); XMP_stream_dict = pdf_stream_dict(XMP_stream); pdf_add_dict(XMP_stream_dict, pdf_new_name("Type"), pdf_new_name("Metadata")); pdf_add_dict(XMP_stream_dict, pdf_new_name("Subtype"), pdf_new_name("XML")); pdf_add_stream(XMP_stream, text_ptr[i].text, text_ptr[i].itxt_length); pdf_add_dict(stream_dict, pdf_new_name("Metadata"), pdf_ref_obj(XMP_stream)); pdf_release_obj(XMP_stream); have_XMP = 1; } } } } #endif /* PNG_LIBPNG_VER */ png_read_end(png_ptr, NULL); /* Cleanup */ if (png_info_ptr) png_destroy_info_struct(png_ptr, &png_info_ptr); if (png_ptr) png_destroy_read_struct(&png_ptr, NULL, NULL); pdf_ximage_set_image(ximage, &info, stream); return 0; }