static int ReadPNG(char *Path, unsigned char **ImgData, int *width, int *length) { FILE *f; unsigned char *tmpRow = NULL; unsigned char *Tempstr = NULL; png_structp png_ptr; png_infop info_ptr; png_uint_32 png_width, png_height, scanline_width; int bit_depth, color_type, interlace_type, row; int channels; f = fopen(Path, "r"); if (!f) return (FALSE); /* we have to load the first 4 bytes of the png file, this contains png version info */ Tempstr = calloc(1, 4); if (fread(Tempstr, 1, 4, f) != 4) { free(Tempstr); fclose(f); return (FALSE); } /* check if valid png */ if (png_sig_cmp(Tempstr, (png_size_t) 0, 4)) printf("%s not a png?\n", Path); /* create the png reading structure, errors go to stderr */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fclose(f); free(Tempstr); return (FALSE); } /* allocate info struct */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(f); png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL); free(Tempstr); return (FALSE); } /* set error handling */ #if PNG_LIBPNG_VER_SONUM >= 15 if (setjmp(png_jmpbuf(png_ptr))) #else /*PNG_LIBPNG_VER_SONUM >= 15*/ if (setjmp(png_ptr->jmpbuf)) #endif /*PNG_LIBPNG_VER_SONUM >= 15*/ { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); free(Tempstr); fclose(f); return (FALSE); } /* prepare the reader to ignore all recognized chunks whose data isn't * going to be used, i.e., all chunks recognized by libpng except for * IHDR, PLTE, IDAT, IEND, tRNS, bKGD, gAMA, and sRGB : */ { #ifndef HANDLE_CHUNK_NEVER /* prior to libpng-1.2.5, this macro was internal, so we define it here. */ # define HANDLE_CHUNK_NEVER 1 #endif /* these byte strings were copied from png.h. * If a future libpng version recognizes more chunks, add them * to this list. If a future version of readpng2.c recognizes * more chunks, delete them from this list. */ png_byte png_chunk_types_to_ignore[] = { 99, 72, 82, 77, '\0', /* cHRM */ 104, 73, 83, 84, '\0', /* hIST */ 105, 67, 67, 80, '\0', /* iCCP */ 105, 84, 88, 116, '\0', /* iTXt */ 111, 70, 70, 115, '\0', /* oFFs */ 112, 67, 65, 76, '\0', /* pCAL */ 115, 67, 65, 76, '\0', /* sCAL */ 112, 72, 89, 115, '\0', /* pHYs */ 115, 66, 73, 84, '\0', /* sBIT */ 115, 80, 76, 84, '\0', /* sPLT */ 116, 69, 88, 116, '\0', /* tEXt */ 116, 73, 77, 69, '\0', /* tIME */ 122, 84, 88, 116, '\0' }; /* zTXt */ #define NUM_PNG_CHUNK_TYPES_TO_IGNORE 13 png_set_keep_unknown_chunks(png_ptr, HANDLE_CHUNK_NEVER, png_chunk_types_to_ignore, NUM_PNG_CHUNK_TYPES_TO_IGNORE); } /* set input method */ png_init_io(png_ptr, f); /* tell libpng we have already read some bytes */ png_set_sig_bytes(png_ptr, 4); /* read all info */ png_read_info(png_ptr, info_ptr); /* get some characteristics of the file */ png_get_IHDR(png_ptr, info_ptr, &png_width, &png_height, &bit_depth, &color_type, &interlace_type, NULL, NULL); *width = (int)png_width; *length = (int)png_height; /*expand bit depth */ png_set_expand(png_ptr); png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); /* get size of scanline */ scanline_width = png_get_rowbytes(png_ptr, info_ptr); channels = png_get_channels(png_ptr, info_ptr); /* allocate texture memory */ *ImgData = (unsigned char *)malloc(png_width * png_height * 4); if (channels == 3) tmpRow = (unsigned char *)malloc(scanline_width * sizeof(unsigned char)); /* read the image line by line into the user's buffer */ for (row = 0; row < png_height; row++) { if (channels == 3) { Read3ByteRow(png_ptr, tmpRow, *ImgData, row, png_width); } else png_read_row(png_ptr, (unsigned char *)((*ImgData) + (row * scanline_width)), NULL); } /* finish reading the file */ png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(f); free(Tempstr); if (tmpRow) free(tmpRow); return (TRUE); }
bool GReadBitmapFromFile(const char path[], GBitmap* bitmap) { FILE* file = fopen(path, "rb"); if (NULL == file) { return always_false(); } GAutoFClose afc(file); uint8_t signature[SIGNATURE_BYTES]; if (SIGNATURE_BYTES != fread(signature, 1, SIGNATURE_BYTES, file)) { return always_false(); } if (png_sig_cmp(signature, 0, SIGNATURE_BYTES)) { return always_false(); } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (NULL == png_ptr) { return always_false(); } png_infop info_ptr = png_create_info_struct(png_ptr); if (NULL == info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); return always_false(); } GAutoPNGReader reader(png_ptr, info_ptr); if (setjmp(png_jmpbuf(png_ptr))) { return always_false(); } png_init_io(png_ptr, file); png_set_sig_bytes(png_ptr, SIGNATURE_BYTES); png_read_info(png_ptr, info_ptr); png_uint_32 width, height; int bitDepth, colorType; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bitDepth, &colorType, NULL, NULL, NULL); if (8 != bitDepth) { return always_false(); // TODO: handle other formats } if (png_set_interlace_handling(png_ptr) > 1) { return always_false(); // TODO: support interleave } swizzle_row_proc row_proc = NULL; switch (colorType) { case PNG_COLOR_TYPE_RGB: row_proc = swizzle_rgb_row; break; case PNG_COLOR_TYPE_RGB_ALPHA: row_proc = swizzle_rgba_row; break; default: return always_false(); } png_read_update_info(png_ptr, info_ptr); GAutoFree rowStorage(malloc(png_get_rowbytes(png_ptr, info_ptr))); png_bytep srcRow = (png_bytep)rowStorage.get(); if (!srcRow) { return always_false(); } GAutoFree pixelStorage(malloc(height * width * 4)); GPixel* dstRow = (GPixel*)pixelStorage.get(); if (NULL == dstRow) { return always_false(); } for (int y = 0; y < height; y++) { uint8_t* tmp = srcRow; png_read_rows(png_ptr, &tmp, NULL, 1); row_proc(dstRow, srcRow, width); dstRow += width; } bitmap->fWidth = width; bitmap->fHeight = height; bitmap->fRowBytes = width * 4; bitmap->fPixels = (GPixel*)pixelStorage.detach(); return true; }
bool PngDecoder::readData( Mat& img ) { bool result = false; AutoBuffer<uchar*> _buffer(m_height); uchar** buffer = _buffer; int color = img.channels() > 1; uchar* data = img.data; int step = (int)img.step; if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height ) { png_structp png_ptr = (png_structp)m_png_ptr; png_infop info_ptr = (png_infop)m_info_ptr; png_infop end_info = (png_infop)m_end_info; if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 ) { int y; if( img.depth() == CV_8U && m_bit_depth == 16 ) png_set_strip_16( png_ptr ); else if( !isBigEndian() ) png_set_swap( png_ptr ); if(img.channels() < 4) { /* observation: png_read_image() writes 400 bytes beyond * end of data when reading a 400x118 color png * "mpplus_sand.png". OpenCV crashes even with demo * programs. Looking at the loaded image I'd say we get 4 * bytes per pixel instead of 3 bytes per pixel. Test * indicate that it is a good idea to always ask for * stripping alpha.. 18.11.2004 Axel Walthelm */ png_set_strip_alpha( png_ptr ); } if( m_color_type == PNG_COLOR_TYPE_PALETTE ) png_set_palette_to_rgb( png_ptr ); if( m_color_type == PNG_COLOR_TYPE_GRAY && m_bit_depth < 8 ) #if (PNG_LIBPNG_VER_MAJOR*10000 + PNG_LIBPNG_VER_MINOR*100 + PNG_LIBPNG_VER_RELEASE >= 10209) || \ (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR == 0 && PNG_LIBPNG_VER_RELEASE >= 18) png_set_expand_gray_1_2_4_to_8( png_ptr ); #else png_set_gray_1_2_4_to_8( png_ptr ); #endif if( CV_MAT_CN(m_type) > 1 && color ) png_set_bgr( png_ptr ); // convert RGB to BGR else if( color ) png_set_gray_to_rgb( png_ptr ); // Gray->RGB else png_set_rgb_to_gray( png_ptr, 1, 0.299, 0.587 ); // RGB->Gray png_set_interlace_handling( png_ptr ); png_read_update_info( png_ptr, info_ptr ); for( y = 0; y < m_height; y++ ) buffer[y] = data + y*step; png_read_image( png_ptr, buffer ); png_read_end( png_ptr, end_info ); result = true; } } close(); return result; }
Load_SBit_Png( FT_GlyphSlot slot, FT_Int x_offset, FT_Int y_offset, FT_Int pix_bits, TT_SBit_Metrics metrics, FT_Memory memory, FT_Byte* data, FT_UInt png_len, FT_Bool populate_map_and_metrics, FT_Bool metrics_only ) { FT_Bitmap *map = &slot->bitmap; FT_Error error = FT_Err_Ok; FT_StreamRec stream; png_structp png; png_infop info; png_uint_32 imgWidth, imgHeight; int bitdepth, color_type, interlace; FT_Int i; png_byte* *rows = NULL; /* pacify compiler */ if ( x_offset < 0 || y_offset < 0 ) { error = FT_THROW( Invalid_Argument ); goto Exit; } if ( !populate_map_and_metrics && ( x_offset + metrics->width > map->width || y_offset + metrics->height > map->rows || pix_bits != 32 || map->pixel_mode != FT_PIXEL_MODE_BGRA ) ) { error = FT_THROW( Invalid_Argument ); goto Exit; } FT_Stream_OpenMemory( &stream, data, png_len ); png = png_create_read_struct( PNG_LIBPNG_VER_STRING, &error, error_callback, warning_callback ); if ( !png ) { error = FT_THROW( Out_Of_Memory ); goto Exit; } info = png_create_info_struct( png ); if ( !info ) { error = FT_THROW( Out_Of_Memory ); png_destroy_read_struct( &png, NULL, NULL ); goto Exit; } if ( ft_setjmp( png_jmpbuf( png ) ) ) { error = FT_THROW( Invalid_File_Format ); goto DestroyExit; } png_set_read_fn( png, &stream, read_data_from_FT_Stream ); png_read_info( png, info ); png_get_IHDR( png, info, &imgWidth, &imgHeight, &bitdepth, &color_type, &interlace, NULL, NULL ); if ( error || ( !populate_map_and_metrics && ( (FT_Int)imgWidth != metrics->width || (FT_Int)imgHeight != metrics->height ) ) ) goto DestroyExit; if ( populate_map_and_metrics ) { metrics->width = (FT_UShort)imgWidth; metrics->height = (FT_UShort)imgHeight; map->width = metrics->width; map->rows = metrics->height; map->pixel_mode = FT_PIXEL_MODE_BGRA; map->pitch = (int)( map->width * 4 ); map->num_grays = 256; /* reject too large bitmaps similarly to the rasterizer */ if ( map->rows > 0x4FFF || map->width > 0x4FFF ) { error = FT_THROW( Array_Too_Large ); goto DestroyExit; } } /* convert palette/gray image to rgb */ if ( color_type == PNG_COLOR_TYPE_PALETTE ) png_set_palette_to_rgb( png ); /* expand gray bit depth if needed */ if ( color_type == PNG_COLOR_TYPE_GRAY ) { #if PNG_LIBPNG_VER >= 10209 png_set_expand_gray_1_2_4_to_8( png ); #else png_set_gray_1_2_4_to_8( png ); #endif } /* transform transparency to alpha */ if ( png_get_valid(png, info, PNG_INFO_tRNS ) ) png_set_tRNS_to_alpha( png ); if ( bitdepth == 16 ) png_set_strip_16( png ); if ( bitdepth < 8 ) png_set_packing( png ); /* convert grayscale to RGB */ if ( color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) png_set_gray_to_rgb( png ); if ( interlace != PNG_INTERLACE_NONE ) png_set_interlace_handling( png ); png_set_filler( png, 0xFF, PNG_FILLER_AFTER ); /* recheck header after setting EXPAND options */ png_read_update_info(png, info ); png_get_IHDR( png, info, &imgWidth, &imgHeight, &bitdepth, &color_type, &interlace, NULL, NULL ); if ( bitdepth != 8 || !( color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA ) ) { error = FT_THROW( Invalid_File_Format ); goto DestroyExit; } if ( metrics_only ) goto DestroyExit; switch ( color_type ) { default: /* Shouldn't happen, but fall through. */ case PNG_COLOR_TYPE_RGB_ALPHA: png_set_read_user_transform_fn( png, premultiply_data ); break; case PNG_COLOR_TYPE_RGB: /* Humm, this smells. Carry on though. */ png_set_read_user_transform_fn( png, convert_bytes_to_data ); break; } if ( populate_map_and_metrics ) { /* this doesn't overflow: 0x4FFF * 0x4FFF * 4 < 2^31 */ FT_ULong size = map->rows * (FT_ULong)map->pitch; error = ft_glyphslot_alloc_bitmap( slot, size ); if ( error ) goto DestroyExit; } if ( FT_NEW_ARRAY( rows, imgHeight ) ) { error = FT_THROW( Out_Of_Memory ); goto DestroyExit; } for ( i = 0; i < (FT_Int)imgHeight; i++ ) rows[i] = map->buffer + ( y_offset + i ) * map->pitch + x_offset * 4; png_read_image( png, rows ); FT_FREE( rows ); png_read_end( png, info ); DestroyExit: png_destroy_read_struct( &png, &info, NULL ); FT_Stream_Close( &stream ); Exit: return error; }
static FT_Error Load_SBit_Png( FT_Bitmap* map, FT_Int x_offset, FT_Int y_offset, FT_Int pix_bits, TT_SBit_Metrics metrics, FT_Memory memory, FT_Byte* data, FT_UInt png_len ) { FT_Error error = FT_Err_Ok; FT_StreamRec stream; png_structp png; png_infop info; png_uint_32 imgWidth, imgHeight; int bitdepth, color_type, interlace; FT_Int i; png_byte* *rows; if ( x_offset < 0 || x_offset + metrics->width > map->width || y_offset < 0 || y_offset + metrics->height > map->rows || pix_bits != 32 || map->pixel_mode != FT_PIXEL_MODE_BGRA ) { error = FT_THROW( Invalid_Argument ); goto Exit; } FT_Stream_OpenMemory( &stream, data, png_len ); png = png_create_read_struct( PNG_LIBPNG_VER_STRING, &error, error_callback, warning_callback ); if ( !png ) { error = FT_THROW( Out_Of_Memory ); goto Exit; } info = png_create_info_struct( png ); if ( !info ) { error = FT_THROW( Out_Of_Memory ); png_destroy_read_struct( &png, NULL, NULL ); goto Exit; } if ( ft_setjmp( png_jmpbuf( png ) ) ) { error = FT_THROW( Invalid_File_Format ); goto DestroyExit; } png_set_read_fn( png, &stream, read_data_from_FT_Stream ); png_read_info( png, info ); png_get_IHDR( png, info, &imgWidth, &imgHeight, &bitdepth, &color_type, &interlace, NULL, NULL ); if ( error != FT_Err_Ok || (FT_Int)imgWidth != metrics->width || (FT_Int)imgHeight != metrics->height ) goto DestroyExit; /* convert palette/gray image to rgb */ if ( color_type == PNG_COLOR_TYPE_PALETTE ) png_set_palette_to_rgb( png ); /* expand gray bit depth if needed */ if ( color_type == PNG_COLOR_TYPE_GRAY ) { #if PNG_LIBPNG_VER >= 10209 png_set_expand_gray_1_2_4_to_8( png ); #else png_set_gray_1_2_4_to_8( png ); #endif } /* transform transparency to alpha */ if ( png_get_valid(png, info, PNG_INFO_tRNS ) ) png_set_tRNS_to_alpha( png ); if ( bitdepth == 16 ) png_set_strip_16( png ); if ( bitdepth < 8 ) png_set_packing( png ); /* convert grayscale to RGB */ if ( color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) png_set_gray_to_rgb( png ); if ( interlace != PNG_INTERLACE_NONE ) png_set_interlace_handling( png ); png_set_filler( png, 0xFF, PNG_FILLER_AFTER ); /* recheck header after setting EXPAND options */ png_read_update_info(png, info ); png_get_IHDR( png, info, &imgWidth, &imgHeight, &bitdepth, &color_type, &interlace, NULL, NULL ); if ( bitdepth != 8 || !( color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA ) ) { error = FT_THROW( Invalid_File_Format ); goto DestroyExit; } switch ( color_type ) { default: /* Shouldn't happen, but fall through. */ case PNG_COLOR_TYPE_RGB_ALPHA: png_set_read_user_transform_fn( png, premultiply_data ); break; case PNG_COLOR_TYPE_RGB: /* Humm, this smells. Carry on though. */ png_set_read_user_transform_fn( png, convert_bytes_to_data ); break; } if ( FT_NEW_ARRAY( rows, imgHeight ) ) { error = FT_THROW( Out_Of_Memory ); goto DestroyExit; } for ( i = 0; i < (FT_Int)imgHeight; i++ ) rows[i] = map->buffer + ( y_offset + i ) * map->pitch + x_offset * 4; png_read_image( png, rows ); FT_FREE( rows ); png_read_end( png, info ); DestroyExit: png_destroy_read_struct( &png, &info, NULL ); FT_Stream_Close( &stream ); Exit: return error; }
// // In order to avoid CRT mismatches, we override all CRT functions libpng uses // with our own. The alternative, using fopen and fread in our code and then // passing a FILE* into libpng, isn't reliable because it crashes if libpng was // compiled with a different CRT than lsapi.dll // HBITMAP LoadFromPNG(LPCSTR pszFilename) { HBITMAP hDibSection = NULL; if (pszFilename != NULL) { FILE * hFile = fopen(pszFilename, "rb"); if (hFile) { const size_t num_sig_bytes = 8; unsigned char sig[num_sig_bytes]; fread(sig, 1, num_sig_bytes, hFile); if (png_check_sig(sig, num_sig_bytes)) { PNGERROR PngError = { 0 }; PngError.Wnd = GetForegroundWindow(); png_structp Read = png_create_read_struct_2( PNG_LIBPNG_VER_STRING, &PngError, PNGErrorHandler, NULL, NULL, ls_png_malloc, ls_png_free); if (Read) { png_infop Info = png_create_info_struct(Read); if (Info) { if (!setjmp(PngError.ErrorJump)) { png_set_read_fn(Read, hFile, ls_png_read_data); png_set_sig_bytes(Read, num_sig_bytes); png_read_info(Read, Info); const unsigned char bit_depth = png_get_bit_depth(Read, Info); const unsigned char color_type = png_get_color_type(Read, Info); if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(Read); } if ((color_type == PNG_COLOR_TYPE_GRAY) || (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) { if (bit_depth < 8) { png_set_gray_1_2_4_to_8(Read); } png_set_gray_to_rgb(Read); } if (png_get_valid(Read, Info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(Read); } if (color_type & PNG_COLOR_MASK_COLOR) { png_set_bgr(Read); } if (bit_depth == 16) { png_set_strip_16(Read); } double image_gamma = 1 / 2.2; png_get_gAMA(Read, Info, &image_gamma); png_set_gamma(Read, 2.2, image_gamma); const int num_passes = png_set_interlace_handling(Read); png_read_update_info(Read, Info); BITMAPINFO bmi = { {0} }; bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = (LONG)png_get_image_width(Read, Info); bmi.bmiHeader.biHeight = -(LONG)png_get_image_height(Read, Info); bmi.bmiHeader.biBitCount = (WORD)(png_get_channels(Read, Info) * png_get_bit_depth(Read, Info)); bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biCompression = BI_RGB; unsigned char* bits; hDibSection = CreateDIBSection(NULL, &bmi, 0, reinterpret_cast<LPVOID*>(&bits), NULL, 0); if (!bits) { longjmp(PngError.ErrorJump, 1); } unsigned int dib_bytes_per_scanline = \ (((bmi.bmiHeader.biWidth * bmi.bmiHeader.biBitCount) + 31) & ~31) >> 3; for (int Pass = 0; Pass < num_passes; ++Pass) { for (int y = 0; y < -bmi.bmiHeader.biHeight; ++y) { unsigned char* Scanline = \ reinterpret_cast<unsigned char*>(bits + (y * dib_bytes_per_scanline)); png_read_row(Read, Scanline, NULL); } } png_read_end(Read, Info); png_destroy_read_struct(&Read, &Info, NULL); } else { png_destroy_read_struct(&Read, &Info, NULL); } } else { png_destroy_read_struct(&Read, NULL, NULL); } }
int image_png_load(MediaScanImage *i) { int bit_depth, color_type, num_passes, x, y; int ofs; volatile unsigned char *ptr = NULL; // volatile = won't be rolled back if longjmp is called PNGData *p = (PNGData *)i->_png; if (setjmp(png_jmpbuf(p->png_ptr))) { if (ptr != NULL) free((void *)ptr); image_png_destroy(i); return 0; } // XXX If reusing the object a second time, we need to completely create a new png struct bit_depth = png_get_bit_depth(p->png_ptr, p->info_ptr); color_type = png_get_color_type(p->png_ptr, p->info_ptr); if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_expand(p->png_ptr); // png_set_palette_to_rgb(p->png_ptr); i->channels = 4; } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(p->png_ptr); // png_set_expand_gray_1_2_4_to_8(p->png_ptr); else if (png_get_valid(p->png_ptr, p->info_ptr, PNG_INFO_tRNS)) png_set_expand(p->png_ptr); // png_set_tRNS_to_alpha(p->png_ptr); if (bit_depth == 16) png_set_strip_16(p->png_ptr); else if (bit_depth < 8) png_set_packing(p->png_ptr); // Make non-alpha RGB/Palette 32-bit and Gray 16-bit for easier handling if (!(color_type & PNG_COLOR_MASK_ALPHA)) { png_set_add_alpha(p->png_ptr, 0xFF, PNG_FILLER_AFTER); } num_passes = png_set_interlace_handling(p->png_ptr); LOG_DEBUG("png bit_depth %d, color_type %d, channels %d, num_passes %d\n", bit_depth, color_type, i->channels, num_passes); png_read_update_info(p->png_ptr, p->info_ptr); image_alloc_pixbuf(i, i->width, i->height); ptr = (unsigned char *)malloc(png_get_rowbytes(p->png_ptr, p->info_ptr)); ofs = 0; if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { // Grayscale (Alpha) if (num_passes == 1) { // Non-interlaced for (y = 0; y < i->height; y++) { png_read_row(p->png_ptr, (unsigned char *)ptr, NULL); for (x = 0; x < i->width; x++) { i->_pixbuf[ofs++] = COL_FULL(ptr[x * 2], ptr[x * 2], ptr[x * 2], ptr[x * 2 + 1]); } } } else if (num_passes == 7) { // Interlaced image_png_interlace_pass_gray(i, (unsigned char *)ptr, 0, 8, 0, 8); image_png_interlace_pass_gray(i, (unsigned char *)ptr, 0, 8, 4, 8); image_png_interlace_pass_gray(i, (unsigned char *)ptr, 4, 8, 0, 4); image_png_interlace_pass_gray(i, (unsigned char *)ptr, 0, 4, 2, 4); image_png_interlace_pass_gray(i, (unsigned char *)ptr, 2, 4, 0, 2); image_png_interlace_pass_gray(i, (unsigned char *)ptr, 0, 2, 1, 2); image_png_interlace_pass_gray(i, (unsigned char *)ptr, 1, 2, 0, 1); } } else { // RGB(A) if (num_passes == 1) { // Non-interlaced for (y = 0; y < i->height; y++) { png_read_row(p->png_ptr, (unsigned char *)ptr, NULL); for (x = 0; x < i->width; x++) { i->_pixbuf[ofs++] = COL_FULL(ptr[x * 4], ptr[x * 4 + 1], ptr[x * 4 + 2], ptr[x * 4 + 3]); } } } else if (num_passes == 7) { // Interlaced // The first pass will return an image 1/8 as wide as the entire image // (every 8th column starting in column 0) // and 1/8 as high as the original (every 8th row starting in row 0) image_png_interlace_pass(i, (unsigned char *)ptr, 0, 8, 0, 8); // The second will be 1/8 as wide (starting in column 4) // and 1/8 as high (also starting in row 0) image_png_interlace_pass(i, (unsigned char *)ptr, 0, 8, 4, 8); // The third pass will be 1/4 as wide (every 4th pixel starting in column 0) // and 1/8 as high (every 8th row starting in row 4) image_png_interlace_pass(i, (unsigned char *)ptr, 4, 8, 0, 4); // The fourth pass will be 1/4 as wide and 1/4 as high // (every 4th column starting in column 2, and every 4th row starting in row 0) image_png_interlace_pass(i, (unsigned char *)ptr, 0, 4, 2, 4); // The fifth pass will return an image 1/2 as wide, // and 1/4 as high (starting at column 0 and row 2) image_png_interlace_pass(i, (unsigned char *)ptr, 2, 4, 0, 2); // The sixth pass will be 1/2 as wide and 1/2 as high as the original // (starting in column 1 and row 0) image_png_interlace_pass(i, (unsigned char *)ptr, 0, 2, 1, 2); // The seventh pass will be as wide as the original, and 1/2 as high, // containing all of the odd numbered scanlines. image_png_interlace_pass(i, (unsigned char *)ptr, 1, 2, 0, 1); } else { FATAL("Unsupported PNG interlace type (%d passes)\n", num_passes); } } free((void *)ptr); // This is not required, so we can save some time by not reading post-image chunks //png_read_end(p->png_ptr, p->info_ptr); return 1; }
void ossimPngReader::restart() { if ( m_str ) { // Destroy the existing memory associated with png structs. if (m_pngReadPtr && m_pngReadInfoPtr) { png_destroy_read_struct(&m_pngReadPtr, &m_pngReadInfoPtr, NULL); } m_pngReadPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); m_pngReadInfoPtr = png_create_info_struct(m_pngReadPtr); if ( setjmp( png_jmpbuf(m_pngReadPtr) ) ) { ossimNotify(ossimNotifyLevel_WARN) << "Error while reading. File corrupted? " << theImageFile << std::endl; return; } // Reset the file pointer. m_str->seekg( m_restartPosition, std::ios_base::beg ); //--- // Pass the static read method to libpng to allow us to use our // c++ stream instead of doing "png_init_io (pp, ...);" with // c stream. //--- png_set_read_fn( m_pngReadPtr, (png_voidp)m_str, (png_rw_ptr)&ossimPngReader::pngReadData ); //--- // Note we won't do png_set_sig_bytes(png_ptr, 8) here because we are not // rechecking for png signature. //--- png_read_info(m_pngReadPtr, m_pngReadInfoPtr); //--- // If png_set_expand used: // Expand data to 24-bit RGB, or 8-bit grayscale, // with alpha if available. //--- bool expandFlag = false; if ( m_pngColorType == PNG_COLOR_TYPE_PALETTE ) { expandFlag = true; } if ( (m_pngColorType == PNG_COLOR_TYPE_GRAY) && (m_bitDepth < 8) ) { expandFlag = true; } if ( png_get_valid(m_pngReadPtr, m_pngReadInfoPtr, PNG_INFO_tRNS) ) { expandFlag = true; } //--- // If png_set_packing used: // Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ //--- bool packingFlag = false; if ( (m_bitDepth < 8) && (m_pngColorType == PNG_COLOR_TYPE_GRAY) ) { packingFlag = true; } if (expandFlag) { png_set_expand(m_pngReadPtr); } if (packingFlag) { png_set_packing(m_pngReadPtr); } // Gamma correction. // ossim_float64 gamma; // if (png_get_gAMA(m_pngReadPtr, m_pngReadInfoPtr, &gamma)) // { // png_set_gamma(m_pngReadPtr, display_exponent, gamma); // } //--- // Turn on interlace handling... libpng returns just 1 (ie single pass) // if the image is not interlaced //--- png_set_interlace_handling (m_pngReadPtr); //--- // Update the info structures after the transformations take effect //--- png_read_update_info (m_pngReadPtr, m_pngReadInfoPtr); // We're back on row 0 or first line. m_currentRow = 0; } }
bool ossimPngReader::initReader() { bool result = true; ossim_uint32 height = png_get_image_height(m_pngReadPtr, m_pngReadInfoPtr); ossim_uint32 width = png_get_image_width(m_pngReadPtr, m_pngReadInfoPtr); m_bitDepth = png_get_bit_depth(m_pngReadPtr, m_pngReadInfoPtr); m_pngColorType = png_get_color_type(m_pngReadPtr, m_pngReadInfoPtr); m_imageRect = ossimIrect(0, 0, width - 1, height - 1); if (m_bitDepth == 16) { // png_set_strip_16 (m_pngReadPtr); m_bytePerPixelPerBand = 2; m_outputScalarType = OSSIM_UINT16; } else { m_bytePerPixelPerBand = 1; } // Set the read mode from scalar and color type. if (m_outputScalarType == OSSIM_UINT8) { if ( (m_pngColorType == PNG_COLOR_TYPE_RGB_ALPHA) || (m_pngColorType == PNG_COLOR_TYPE_GRAY_ALPHA) ) { m_readMode = ossimPngRead8a; } else { m_readMode = ossimPngRead8; } } else { if ( (m_pngColorType == PNG_COLOR_TYPE_RGB_ALPHA) || (m_pngColorType == PNG_COLOR_TYPE_GRAY_ALPHA) ) { m_readMode = ossimPngRead16a; } else { m_readMode = ossimPngRead16; } // Set the swap flag. PNG stores data in network byte order(big endian). if(ossim::byteOrder() == OSSIM_LITTLE_ENDIAN) { m_swapFlag = true; } } //--- // If png_set_expand used: // Expand data to 24-bit RGB, or 8-bit grayscale, // with alpha if available. //--- bool expandFlag = false; if ( m_pngColorType == PNG_COLOR_TYPE_PALETTE ) { expandFlag = true; } if ( (m_pngColorType == PNG_COLOR_TYPE_GRAY) && (m_bitDepth < 8) ) { expandFlag = true; } if ( png_get_valid(m_pngReadPtr, m_pngReadInfoPtr, PNG_INFO_tRNS) ) { expandFlag = true; } //--- // If png_set_packing used: // Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ //--- bool packingFlag = false; if ( (m_bitDepth < 8) && (m_pngColorType == PNG_COLOR_TYPE_GRAY) ) { packingFlag = true; } if (expandFlag) { png_set_expand(m_pngReadPtr); } if (packingFlag) { png_set_packing(m_pngReadPtr); } // Gamma correction. // ossim_float64 gamma; // if (png_get_gAMA(m_pngReadPtr, m_pngReadInfoPtr, &gamma)) // { // png_set_gamma(png_ptr, display_exponent, gamma); // } //--- // Turn on interlace handling... libpng returns just 1 (ie single pass) // if the image is not interlaced //--- m_interlacePasses = png_set_interlace_handling (m_pngReadPtr); //--- // Update the info structures after the transformations take effect //--- png_read_update_info (m_pngReadPtr, m_pngReadInfoPtr); // TODO: // Add check for image offsets. // Add check for resolution. // Add check for colormap. switch (m_pngColorType) { case PNG_COLOR_TYPE_RGB: /* RGB */ { m_numberOfInputBands = 3; m_numberOfOutputBands = 3; break; } case PNG_COLOR_TYPE_RGB_ALPHA: /* RGBA */ { m_numberOfInputBands = 4; if (m_useAlphaChannelFlag) { m_numberOfOutputBands = 4; } else { m_numberOfOutputBands = 3; } break; } case PNG_COLOR_TYPE_GRAY: /* Grayscale */ { m_numberOfInputBands = 1; m_numberOfOutputBands = 1; break; } case PNG_COLOR_TYPE_GRAY_ALPHA: /* Grayscale + alpha */ { m_numberOfInputBands = 2; if (m_useAlphaChannelFlag) { m_numberOfOutputBands = 2; } else { m_numberOfOutputBands = 1; } break; } case PNG_COLOR_TYPE_PALETTE: /* Indexed */ { m_numberOfInputBands = 3; m_numberOfOutputBands = 3; break; } default: /* Unknown type */ { result = false; } } if ( result ) { m_lineBufferSizeInBytes = png_get_rowbytes(m_pngReadPtr, m_pngReadInfoPtr); // Set the max pixel value. setMaxPixelValue(); // Set to OSSIM_USHORT11 for use of specialized tile. if (m_maxPixelValue[0] == 2047.0) { m_outputScalarType = OSSIM_USHORT11; } // We're on row 0 or first line. m_currentRow = 0; if (traceDebug()) { ossimNotify(ossimNotifyLevel_DEBUG) << "ossimPngReader::initReader DEBUG:" << "\nm_imageRect: " << m_imageRect << "\nm_bitDepth: " << int(m_bitDepth) << "\nm_pngColorType: " << getPngColorTypeString().c_str() << "\nm_numberOfInputBands: " << m_numberOfInputBands << "\nm_numberOfOutputBands: " << m_numberOfOutputBands << "\nm_bytePerPixelPerBand: " << m_bytePerPixelPerBand << "\nm_lineBufferSizeInBytes: " << m_lineBufferSizeInBytes << "\nm_interlacePasses: " << m_interlacePasses << "\npalette expansion: " << (expandFlag?"on":"off") << "\npacking (1,2,4 bit to one byte): " << (packingFlag?"on":"off") << "\nm_readMode: " << m_readMode << "\nm_swapFlag: " << m_swapFlag << std::endl; for (ossim_uint32 band = 0; band < m_numberOfInputBands; ++band) { ossimNotify(ossimNotifyLevel_DEBUG) << "max[" << band << "]: " << m_maxPixelValue[band] << std::endl; } } } return result; } // End: ossimPngReader::initReader()
void LoadPNG( const char *name, byte **pic, int *width, int *height, int *numLayers, int *numMips, int *bits, byte alphaByte ) { int bit_depth; int color_type; png_uint_32 w; png_uint_32 h; unsigned int row; png_infop info; png_structp png; png_bytep *row_pointers; byte *data; byte *out; // load png ri.FS_ReadFile( name, ( void ** ) &data ); if ( !data ) { return; } png = png_create_read_struct( PNG_LIBPNG_VER_STRING, ( png_voidp ) nullptr, png_user_error_fn, png_user_warning_fn ); if ( !png ) { ri.Printf( PRINT_WARNING, "LoadPNG: png_create_write_struct() failed for (%s)\n", name ); ri.FS_FreeFile( data ); return; } // allocate/initialize the memory for image information. REQUIRED info = png_create_info_struct( png ); if ( !info ) { ri.Printf( PRINT_WARNING, "LoadPNG: png_create_info_struct() failed for (%s)\n", name ); ri.FS_FreeFile( data ); png_destroy_read_struct( &png, ( png_infopp ) nullptr, ( png_infopp ) nullptr ); return; } /* * Set error handling if you are using the setjmp/longjmp method (this is * the common method of doing things with libpng). REQUIRED unless you * set up your own error handlers in the png_create_read_struct() earlier. */ if ( setjmp( png_jmpbuf( png ) ) ) { // if we get here, we had a problem reading the file ri.Printf( PRINT_WARNING, "LoadPNG: first exception handler called for (%s)\n", name ); ri.FS_FreeFile( data ); png_destroy_read_struct( &png, ( png_infopp ) & info, ( png_infopp ) nullptr ); return; } png_set_read_fn( png, data, png_read_data ); png_set_sig_bytes( png, 0 ); // The call to png_read_info() gives us all of the information from the // PNG file before the first IDAT (image data chunk). REQUIRED png_read_info( png, info ); // get picture info png_get_IHDR( png, info, ( png_uint_32 * ) &w, ( png_uint_32 * ) &h, &bit_depth, &color_type, nullptr, nullptr, nullptr ); // tell libpng to strip 16 bit/color files down to 8 bits/color png_set_strip_16( png ); // expand paletted images to RGB triplets if ( color_type & PNG_COLOR_MASK_PALETTE ) { png_set_expand( png ); } // expand gray-scaled images to RGB triplets if ( !( color_type & PNG_COLOR_MASK_COLOR ) ) { png_set_gray_to_rgb( png ); } // expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel // expand paletted or RGB images with transparency to full alpha channels // so the data will be available as RGBA quartets if ( png_get_valid( png, info, PNG_INFO_tRNS ) ) { png_set_tRNS_to_alpha( png ); } // if there is no alpha information, fill with alphaByte if ( !( color_type & PNG_COLOR_MASK_ALPHA ) ) { png_set_filler( png, alphaByte, PNG_FILLER_AFTER ); } // expand pictures with less than 8bpp to 8bpp if ( bit_depth < 8 ) { png_set_packing( png ); } png_set_interlace_handling( png ); // update structure with the above settings png_read_update_info( png, info ); // allocate the memory to hold the image *width = w; *height = h; *pic = out = ( byte * ) ri.Z_Malloc( w * h * 4 ); row_pointers = ( png_bytep * ) ri.Hunk_AllocateTempMemory( sizeof( png_bytep ) * h ); // set a new exception handler if ( setjmp( png_jmpbuf( png ) ) ) { ri.Printf( PRINT_WARNING, "LoadPNG: second exception handler called for (%s)\n", name ); ri.Hunk_FreeTempMemory( row_pointers ); ri.FS_FreeFile( data ); png_destroy_read_struct( &png, ( png_infopp ) & info, ( png_infopp ) nullptr ); return; } for ( row = 0; row < h; row++ ) { row_pointers[ row ] = ( png_bytep )( out + ( row * 4 * w ) ); } // read image data png_read_image( png, row_pointers ); // read rest of file, and get additional chunks in info png_read_end( png, info ); // clean up after the read, and free any memory allocated png_destroy_read_struct( &png, &info, ( png_infopp ) nullptr ); ri.Hunk_FreeTempMemory( row_pointers ); ri.FS_FreeFile( data ); }
void RGBAUtilities::readPngFile(char* file_name) { char header[8]; // 8 is the maximum size that can be checked /* 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 */ pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!pngPtr) abort_("[read_png_file] png_create_read_struct failed"); infoPtr = png_create_info_struct(pngPtr); if (!infoPtr) abort_("[read_png_file] png_create_info_struct failed"); if (setjmp(png_jmpbuf(pngPtr))) abort_("[read_png_file] Error during init_io"); png_init_io(pngPtr, fp); png_set_sig_bytes(pngPtr, 8); png_read_info(pngPtr, infoPtr); imageWidth = png_get_image_width(pngPtr, infoPtr); imageLength = png_get_image_height(pngPtr, infoPtr); config = png_get_color_type(pngPtr, infoPtr); bitsPerSample = png_get_bit_depth(pngPtr, infoPtr); // = 8 bits numberOfPasses = png_set_interlace_handling(pngPtr); png_read_update_info(pngPtr, infoPtr); imageWidth = png_get_image_width(pngPtr, infoPtr); imageLength = png_get_image_height(pngPtr, infoPtr); samplesPerPixel = png_get_channels(pngPtr, infoPtr); // = 4 bytes bitsPerPixel = samplesPerPixel*bitsPerSample; linebytes = samplesPerPixel * imageWidth; // = 640 //linebytes = png_get_rowbytes(pngPtr, infoPtr); = 640 imageBitSize = (sizeof(uint8) * imageWidth * imageLength * samplesPerPixel); imageSize = imageWidth * imageLength * samplesPerPixel; //printf("linebytes = %i, expected %i\n",linebytes,png_get_rowbytes(pngPtr, infoPtr)); //printf("Image Height is %d", sizeof(png_bytep) * imageLength); /* read file */ if (setjmp(png_jmpbuf(pngPtr))) abort_("[read_png_file] Error during read_image"); rowPointers = (png_bytep*) malloc(sizeof(png_bytep) * imageLength); for (y=0; y<imageLength; y++) rowPointers[y] = (png_byte*) malloc(png_get_rowbytes(pngPtr,infoPtr)); png_read_image(pngPtr, rowPointers); fclose(fp); }
errCode genTextures(const char *rootDir, const sFileList *files, sTex ***dynarrTextures){ static const size_t BUFFLEN = 1024; int numTexs=0; int idxFile = files->num; sTex *refTex; if(idxFile <= 0 || rootDir == NULL || rootDir[0] == '\0' || dynarrTextures == NULL) return PROBLEM; size_t lenRootDir = strlen(rootDir); char filePath[BUFFLEN]; FILE *handFile; png_byte header[PNGHEAD_SIZE]; strncpy(filePath, rootDir, 1024); if(lenRootDir>0 && filePath[lenRootDir-1]!='/'){ filePath[lenRootDir] = '/'; lenRootDir += 1; } while(idxFile > 0){ --idxFile; strncpy(&filePath[lenRootDir], files->dynarrFiles[idxFile], 1024 - lenRootDir); handFile = fopen(filePath, "rb"); if(handFile == NULL){ WARN("Can't open file %s", filePath); continue; } if( fread(header, sizeof(png_byte), PNGHEAD_SIZE, handFile) == PNGHEAD_SIZE && png_sig_cmp(header, 0, PNGHEAD_SIZE) == 0 ){ XTRA_LOG("File %s opened as PNG", filePath); }else{ WARN("File %s isn't a PNG", filePath); fclose(handFile); continue; } ++numTexs; (*dynarrTextures) = (sTex**)realloc_chk((*dynarrTextures), (numTexs+1) * sizeof(sTex*)); (*dynarrTextures)[numTexs]=NULL; refTex = (*dynarrTextures)[numTexs-1] = (sTex*)malloc_chk(sizeof(sTex)); memset(refTex, 0, sizeof(sTex)); refTex->pngptrData = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, &myPNGWarnFoo ); if(refTex->pngptrData == NULL){ WARN("Unable to create png struct"); fclose(handFile); continue; } if(setjmp(png_jmpbuf(refTex->pngptrData)) != 0){ /** jumps here on errors. */ cleanupPNGImg( refTex->pngptrData, &refTex->dynarrRows ); png_destroy_read_struct( &(refTex->pngptrData), &(refTex->pngptrInfo), NULL ); refTex->h = refTex->w = 0; }else{ refTex->pngptrInfo = png_create_info_struct( refTex->pngptrData ); if(refTex->pngptrInfo == NULL){ WARN("Unable to create png info struct"); fclose(handFile); continue; } /** setup PNG decode */ png_init_io(refTex->pngptrData, handFile); png_set_sig_bytes(refTex->pngptrData, PNGHEAD_SIZE); png_read_info(refTex->pngptrData, refTex->pngptrInfo); png_byte colorCurrent = png_get_color_type( refTex->pngptrData, refTex->pngptrInfo ); png_set_filler(refTex->pngptrData, 0, PNG_FILLER_AFTER); png_set_packing(refTex->pngptrData); /** if < 8 bits */ { png_color_8p sig_bit; if (png_get_sBIT(refTex->pngptrData, refTex->pngptrInfo, &sig_bit)) png_set_shift(refTex->pngptrData, sig_bit); } switch(colorCurrent){ case PNG_COLOR_TYPE_RGB_ALPHA: /** already good */ break; case PNG_COLOR_TYPE_RGB: png_set_tRNS_to_alpha(refTex->pngptrData); break; case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb( refTex->pngptrData ); png_set_tRNS_to_alpha(refTex->pngptrData); break; case PNG_COLOR_TYPE_GRAY: png_set_expand_gray_1_2_4_to_8( refTex->pngptrData ); png_set_tRNS_to_alpha(refTex->pngptrData); break; default: WARN("unsupported colour"); break; } png_read_update_info(refTex->pngptrData, refTex->pngptrInfo); colorCurrent = png_get_color_type( refTex->pngptrData, refTex->pngptrInfo ); if(colorCurrent != PNG_COLOR_TYPE_RGB_ALPHA){ printf("<warning> %s didn't convert to the right colour type\n", files->dynarrFiles[idxFile]); png_destroy_read_struct(&refTex->pngptrData, &refTex->pngptrInfo, (png_infopp)NULL); fclose(handFile); continue; } refTex->colorType = colorCurrent; const int numPasses = png_set_interlace_handling( refTex->pngptrData ); /** setup other data */ copyString(&refTex->name, files->dynarrFiles[idxFile]); /** setup texture */ unsigned int row; const png_uint_32 sizeRow = png_get_rowbytes( refTex->pngptrData, refTex->pngptrInfo ); refTex->w = png_get_image_width( refTex->pngptrData, refTex->pngptrInfo ); refTex->h = png_get_image_height( refTex->pngptrData, refTex->pngptrInfo ); if(sizeRow/refTex->w != DEFAULT_BYTE_PP){ WARN("%s didn't convert to the right bit depth", refTex->name); png_destroy_read_struct(&refTex->pngptrData, &refTex->pngptrInfo, (png_infopp)NULL); fclose(handFile); continue; } refTex->dynarrRows = calloc_chk((refTex->h +1), sizeof(png_byte*)); refTex->dynarrRows[refTex->h] = NULL; for(row = 0; row < refTex->h; ++row) refTex->dynarrRows[row] = png_malloc(refTex->pngptrData, sizeRow); unsigned int pass; for(pass=0; pass < numPasses; ++pass){ for(row = 0; row < refTex->h; ++row){ png_read_rows( refTex->pngptrData, &refTex->dynarrRows[row], NULL, 1 ); } } png_read_end(refTex->pngptrData, refTex->pngptrInfo); } fclose(handFile); } return NOPROB; }
void PNGImageDecoder::headerAvailable() { png_structp png = m_reader->pngPtr(); png_infop info = m_reader->infoPtr(); png_uint_32 width = png_get_image_width(png, info); png_uint_32 height = png_get_image_height(png, info); // Protect against large images. if (width > cMaxPNGSize || height > cMaxPNGSize) { longjmp(JMPBUF(png), 1); return; } // We can fill in the size now that the header is available. Avoid memory // corruption issues by neutering setFailed() during this call; if we don't // do this, failures will cause |m_reader| to be deleted, and our jmpbuf // will cease to exist. Note that we'll still properly set the failure flag // in this case as soon as we longjmp(). m_doNothingOnFailure = true; bool result = setSize(width, height); m_doNothingOnFailure = false; if (!result) { longjmp(JMPBUF(png), 1); return; } int bitDepth, colorType, interlaceType, compressionType, filterType, channels; png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType, &interlaceType, &compressionType, &filterType); if ((colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_RGB_ALPHA) && !m_ignoreGammaAndColorProfile) { // We currently support color profiles only for RGB and RGBA PNGs. Supporting // color profiles for gray-scale images is slightly tricky, at least using the // CoreGraphics ICC library, because we expand gray-scale images to RGB but we // don't similarly transform the color profile. We'd either need to transform // the color profile or we'd need to decode into a gray-scale image buffer and // hand that to CoreGraphics. m_colorProfile = readColorProfile(png, info); } // The options we set here match what Mozilla does. // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA. if (colorType == PNG_COLOR_TYPE_PALETTE || (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8)) png_set_expand(png); png_bytep trns = 0; int trnsCount = 0; if (png_get_valid(png, info, PNG_INFO_tRNS)) { png_get_tRNS(png, info, &trns, &trnsCount, 0); png_set_expand(png); } if (bitDepth == 16) png_set_strip_16(png); if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); // Deal with gamma and keep it under our control. double gamma; if (!m_ignoreGammaAndColorProfile && png_get_gAMA(png, info, &gamma)) { if ((gamma <= 0.0) || (gamma > cMaxGamma)) { gamma = cInverseGamma; png_set_gAMA(png, info, gamma); } png_set_gamma(png, cDefaultGamma, gamma); } else png_set_gamma(png, cDefaultGamma, cInverseGamma); // Tell libpng to send us rows for interlaced pngs. if (interlaceType == PNG_INTERLACE_ADAM7) png_set_interlace_handling(png); // Update our info now. png_read_update_info(png, info); channels = png_get_channels(png, info); ASSERT(channels == 3 || channels == 4); m_reader->setHasAlpha(channels == 4); if (m_reader->decodingSizeOnly()) { // If we only needed the size, halt the reader. #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 } }
/* Write a VIPS image to PNG. */ static int write_vips( Write *write, int compress, int interlace, const char *profile, VipsForeignPngFilter filter, gboolean strip, gboolean palette, int colours, int Q, double dither ) { VipsImage *in = write->in; int bit_depth; int color_type; int interlace_type; int i, nb_passes; g_assert( in->BandFmt == VIPS_FORMAT_UCHAR || in->BandFmt == VIPS_FORMAT_USHORT ); g_assert( in->Coding == VIPS_CODING_NONE ); g_assert( in->Bands > 0 && in->Bands < 5 ); /* Catch PNG errors. */ if( setjmp( png_jmpbuf( write->pPng ) ) ) return( -1 ); /* Check input image. If we are writing interlaced, we need to make 7 * passes over the image. We advertise ourselves as seq, so to ensure * we only suck once from upstream, switch to WIO. */ if( interlace ) { if( !(write->memory = vips_image_copy_memory( in )) ) return( -1 ); in = write->memory; } else { if( vips_image_pio_input( in ) ) return( -1 ); } if( compress < 0 || compress > 9 ) { vips_error( "vips2png", "%s", _( "compress should be in [0,9]" ) ); return( -1 ); } /* Set compression parameters. */ png_set_compression_level( write->pPng, compress ); /* Set row filter. */ png_set_filter( write->pPng, 0, filter ); bit_depth = in->BandFmt == VIPS_FORMAT_UCHAR ? 8 : 16; switch( in->Bands ) { case 1: color_type = PNG_COLOR_TYPE_GRAY; break; case 2: color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break; case 3: color_type = PNG_COLOR_TYPE_RGB; break; case 4: color_type = PNG_COLOR_TYPE_RGB_ALPHA; break; default: vips_error( "vips2png", _( "can't save %d band image as png" ), in->Bands ); return( -1 ); } #ifdef HAVE_IMAGEQUANT /* Enable image quantisation to paletted 8bpp PNG if colours is set. */ if( palette ) { g_assert( colours >= 2 && colours <= 256 ); bit_depth = 8; color_type = PNG_COLOR_TYPE_PALETTE; } #else if( palette ) g_warning( "%s", _( "ignoring palette (no quantisation support)" ) ); #endif /*HAVE_IMAGEQUANT*/ interlace_type = interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE; png_set_IHDR( write->pPng, write->pInfo, in->Xsize, in->Ysize, bit_depth, color_type, interlace_type, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); /* Set resolution. libpng uses pixels per meter. */ png_set_pHYs( write->pPng, write->pInfo, VIPS_RINT( in->Xres * 1000 ), VIPS_RINT( in->Yres * 1000 ), PNG_RESOLUTION_METER ); /* Set ICC Profile. */ if( profile && !strip ) { if( strcmp( profile, "none" ) != 0 ) { void *data; size_t length; if( !(data = vips__file_read_name( profile, vips__icc_dir(), &length )) ) return( -1 ); #ifdef DEBUG printf( "write_vips: " "attaching %zd bytes of ICC profile\n", length ); #endif /*DEBUG*/ png_set_iCCP( write->pPng, write->pInfo, "icc", PNG_COMPRESSION_TYPE_BASE, data, length ); } } else if( vips_image_get_typeof( in, VIPS_META_ICC_NAME ) && !strip ) { void *data; size_t length; if( vips_image_get_blob( in, VIPS_META_ICC_NAME, &data, &length ) ) return( -1 ); #ifdef DEBUG printf( "write_vips: attaching %zd bytes of ICC profile\n", length ); #endif /*DEBUG*/ png_set_iCCP( write->pPng, write->pInfo, "icc", PNG_COMPRESSION_TYPE_BASE, data, length ); } if( vips_image_get_typeof( in, VIPS_META_XMP_NAME ) ) { const char *str; if( vips_image_get_string( in, VIPS_META_XMP_NAME, &str ) ) return( -1 ); vips__png_set_text( write->pPng, write->pInfo, "XML:com.adobe.xmp", str ); } /* Set any "png-comment-xx-yyy" metadata items. */ if( vips_image_map( in, write_png_comment, write ) ) return( -1 ); #ifdef HAVE_IMAGEQUANT if( palette ) { VipsImage *im_index; VipsImage *im_palette; int palette_count; png_color *png_palette; png_byte *png_trans; int trans_count; if( vips__quantise_image( in, &im_index, &im_palette, colours, Q, dither ) ) return( -1 ); palette_count = im_palette->Xsize; g_assert( palette_count <= PNG_MAX_PALETTE_LENGTH ); png_palette = (png_color *) png_malloc( write->pPng, palette_count * sizeof( png_color ) ); png_trans = (png_byte *) png_malloc( write->pPng, palette_count * sizeof( png_byte ) ); trans_count = 0; for( i = 0; i < palette_count; i++ ) { VipsPel *p = (VipsPel *) VIPS_IMAGE_ADDR( im_palette, i, 0 ); png_color *col = &png_palette[i]; col->red = p[0]; col->green = p[1]; col->blue = p[2]; png_trans[i] = p[3]; if( p[3] != 255 ) trans_count = i + 1; #ifdef DEBUG printf( "write_vips: palette[%d] %d %d %d %d\n", i + 1, p[0], p[1], p[2], p[3] ); #endif /*DEBUG*/ } #ifdef DEBUG printf( "write_vips: attaching %d color palette\n", palette_count ); #endif /*DEBUG*/ png_set_PLTE( write->pPng, write->pInfo, png_palette, palette_count ); if( trans_count ) { #ifdef DEBUG printf( "write_vips: attaching %d alpha values\n", trans_count ); #endif /*DEBUG*/ png_set_tRNS( write->pPng, write->pInfo, png_trans, trans_count, NULL ); } png_free( write->pPng, (void *) png_palette ); png_free( write->pPng, (void *) png_trans ); VIPS_UNREF( im_palette ); VIPS_UNREF( write->memory ); write->memory = im_index; in = write->memory; } #endif /*HAVE_IMAGEQUANT*/ png_write_info( write->pPng, write->pInfo ); /* If we're an intel byte order CPU and this is a 16bit image, we need * to swap bytes. */ if( bit_depth > 8 && !vips_amiMSBfirst() ) png_set_swap( write->pPng ); if( interlace ) nb_passes = png_set_interlace_handling( write->pPng ); else nb_passes = 1; /* Write data. */ for( i = 0; i < nb_passes; i++ ) if( vips_sink_disc( in, write_png_block, write ) ) return( -1 ); /* The setjmp() was held by our background writer: reset it. */ if( setjmp( png_jmpbuf( write->pPng ) ) ) return( -1 ); png_write_end( write->pPng, write->pInfo ); return( 0 ); }
static void png_info_callback(png_structp png_ptr, png_infop info_ptr) { int bit_depth, color_type, intent; double gamma; unsigned char bytes_per_pixel=3; struct cached_image *cimg; cimg=global_cimg; bit_depth=png_get_bit_depth(png_ptr, info_ptr); color_type=png_get_color_type(png_ptr, info_ptr); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)){ png_set_expand(png_ptr); /* Legacy version of png_set_tRNS_to_alpha(png_ptr); */ bytes_per_pixel++; } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); if (bit_depth==16){ #ifndef REPACK_16 #ifdef C_LITTLE_ENDIAN /* We use native endianity only if unsigned short is 2-byte * because otherwise we have to reassemble the buffer so we * will leave in the libpng-native big endian. */ png_set_swap(png_ptr); #endif /* #ifdef C_LITTLE_ENDIAN */ #endif /* #ifndef REPACK_16 */ bytes_per_pixel*=(int)sizeof(unsigned short); } png_set_interlace_handling(png_ptr); if (color_type==PNG_COLOR_TYPE_RGB_ALPHA ||color_type==PNG_COLOR_TYPE_GRAY_ALPHA){ if (bytes_per_pixel==3 ||bytes_per_pixel==3*sizeof(unsigned short)) bytes_per_pixel=4*bytes_per_pixel/3; } cimg->width=(int)png_get_image_width(png_ptr,info_ptr); cimg->height=(int)png_get_image_height(png_ptr,info_ptr); cimg->buffer_bytes_per_pixel=bytes_per_pixel; if (png_get_sRGB(png_ptr, info_ptr, &intent)){ gamma=sRGB_gamma; } else { if (!png_get_gAMA(png_ptr, info_ptr, &gamma)){ gamma=sRGB_gamma; } } if (gamma < 0.01 || gamma > 100) gamma = sRGB_gamma; cimg->red_gamma=(float)gamma; cimg->green_gamma=(float)gamma; cimg->blue_gamma=(float)gamma; png_read_update_info(png_ptr,info_ptr); cimg->strip_optimized=0; if (header_dimensions_known(cimg)) img_my_png_error(png_ptr, "bad image size"); }
static FtkBitmap* load_png (const char *filename) { FtkColor bg = {0}; unsigned int x = 0; unsigned int y = 0; png_byte bit_depth = 0; unsigned int width = 0; unsigned int height = 0; int number_of_passes = 0; png_byte color_type = 0; png_infop info_ptr = NULL; png_structp png_ptr = NULL; png_bytep * row_pointers = NULL; char header[8]; // 8 is the maximum size that can be checked int rowbytes = 0; FtkColor* dst = NULL; unsigned char* src = NULL; FtkBitmap* bitmap = NULL; FILE *fp = fopen(filename, "rb"); return_val_if_fail(fp, NULL); bg.a = 0xff; fread(header, 1, 8, fp); return_val_if_fail(png_sig_cmp(header, 0, 8) == 0, NULL); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); return_val_if_fail(png_ptr, NULL); info_ptr = png_create_info_struct(png_ptr); return_val_if_fail(info_ptr, NULL); return_val_if_fail(setjmp(png_jmpbuf(png_ptr)) == 0, NULL); png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); 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); color_type = png_get_color_type(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); number_of_passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); return_val_if_fail(setjmp(png_jmpbuf(png_ptr)) == 0, NULL); rowbytes = png_get_rowbytes(png_ptr,info_ptr); row_pointers = (png_bytep*) FTK_ZALLOC(sizeof(png_bytep) * height); for (y=0; y<height; y++) { row_pointers[y] = (png_byte*) FTK_ZALLOC(rowbytes); } png_read_image(png_ptr, row_pointers); fclose(fp); bitmap = ftk_bitmap_create(width, height, bg); dst = ftk_bitmap_lock(bitmap); if (color_type == PNG_COLOR_TYPE_RGBA) { unsigned int w = width; unsigned int h = height; for(y = 0; y < h; y++) { src = row_pointers[y]; for(x = 0; x < w; x++) { if(src[3]) { dst->r = src[0]; dst->g = src[1]; dst->b = src[2]; dst->a = src[3]; } else { dst->r = 0xff; dst->g = 0xff; dst->b = 0xff; dst->a = 0; } src +=4; dst++; } } } else if(color_type == PNG_COLOR_TYPE_RGB) { unsigned int w = width; unsigned int h = height; for(y = 0; y < h; y++) { src = row_pointers[y]; for(x = 0; x < w; x++) { dst->r = src[0]; dst->g = src[1]; dst->b = src[2]; dst->a = 0xff; src += 3; dst++; } } } else { assert(!"not supported."); } for(y = 0; y < height; y++) { FTK_FREE(row_pointers[y]); } FTK_FREE(row_pointers); return bitmap; }
int fh_png_load(const char *name,unsigned char **buffer,int* /*xp*/,int* /*yp*/) { static const png_color_16 my_background = {0, 0, 0, 0, 0}; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; unsigned int i; int bit_depth, color_type, interlace_type; int number_passes,pass; png_byte * fbptr; FILE * fh; if(!(fh=fopen(name,"rb"))) return(FH_ERROR_FILE); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); if(png_ptr == NULL) { fclose(fh); return(FH_ERROR_FORMAT); } info_ptr = png_create_info_struct(png_ptr); if(info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); fclose(fh); return(FH_ERROR_FORMAT); } if(setjmp(png_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fh); return(FH_ERROR_FORMAT); } png_init_io(png_ptr,fh); png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,&interlace_type, NULL, NULL); if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); png_set_background(png_ptr, (png_color_16*)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); /* other possibility for png_set_background: use png_get_bKGD */ } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); png_set_background(png_ptr, (png_color_16*)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); } /* this test does not trigger for 8bit-paletted PNGs with newer libpng (1.2.36 at least), but the data delivered is with alpha channel anyway, so always strip alpha for now */ #if PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR <= 2 && PNG_LIBPNG_VER_RELEASE < 36 if (color_type & PNG_COLOR_MASK_ALPHA) #endif png_set_strip_alpha(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); /* on Intel PC ?: if (bit_depth == 16) png_set_swap(png_ptr); */ number_passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr,info_ptr); if (width * 3 != png_get_rowbytes(png_ptr, info_ptr)) { printf("[png.cpp]: Error processing %s - please report (including image).\n", name); printf(" width: %lu rowbytes: %lu\n", width, png_get_rowbytes(png_ptr, info_ptr)); fclose(fh); return(FH_ERROR_FORMAT); } for(pass = 0; pass < number_passes; pass++) { fbptr = (png_byte *)(*buffer); for (i = 0; i < height; i++, fbptr += width * 3) { png_read_row(png_ptr, fbptr, NULL); } } png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fh); return(FH_ERROR_OK); }
int PngDecoder::validate() { if (png_sig_cmp((png_bytep)buf->data(), 0, PNG_HEADER_SIZE)) { std::cout << "[PngDecoder] error: %s is not a PNG." << std::endl; return -1; } buf->drain(PNG_HEADER_SIZE); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { std::cout << "[PngDecoder] error: png_create_read_struct returned 0." << std::endl; return -1; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { std::cout << "[PngDecoder] error: png_create_info_struct returned 0." << std::endl; png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return -1; } end_info = png_create_info_struct(png_ptr); if (!end_info) { std::cout << "[PngDecoder] error: png_create_info_struct returned 0." << std::endl; png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); return -1; } if (setjmp(png_jmpbuf(png_ptr))) { std::cout << "[PngDecoder] error from libpng" << std::endl; png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return -1; } png_set_read_fn(png_ptr, buf, pngDecoderReadFunction); png_set_sig_bytes(png_ptr, PNG_HEADER_SIZE); png_read_info(png_ptr, info_ptr); png_set_expand(png_ptr); png_set_strip_16(png_ptr); png_set_gray_to_rgb(png_ptr); png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER); png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); imgInfo.width = png_get_image_width(png_ptr, info_ptr); imgInfo.height = png_get_image_height(png_ptr, info_ptr); imgInfo.color_type = png_get_color_type(png_ptr, info_ptr); imgInfo.channels = png_get_channels(png_ptr, info_ptr); imgInfo.bit_depth = png_get_bit_depth(png_ptr, info_ptr); imgInfo.interlance_type = png_get_interlace_type(png_ptr, info_ptr); imgInfo.rowbytes = png_get_rowbytes(png_ptr, info_ptr); #ifdef _PNGDECODER_DEBUG std::cout << "[PngDecoder] Extracted w=" << imgInfo.width << " h=" << imgInfo.height << " color_type=" << imgInfo.color_type << " bit_depth="<< imgInfo.bit_depth << " rowbytes="<< imgInfo.rowbytes << " channels="<< imgInfo.channels << " interlance_type="<< imgInfo.interlance_type << std::endl; #endif if (imgInfo.bit_depth != 8) { std::cout << "[PngDecoder] error: Unsupported bit depth=" << imgInfo.bit_depth <<". Must be 8." << std::endl; return -1; } switch(imgInfo.color_type) { case PNG_COLOR_TYPE_RGB: imgInfo.format = GL_RGB; break; case PNG_COLOR_TYPE_RGB_ALPHA: imgInfo.format = GL_RGBA; break; case PNG_COLOR_TYPE_PALETTE: if (imgInfo.color_type & PNG_COLOR_MASK_ALPHA) { imgInfo.format = GL_RGBA; } else if (imgInfo.color_type & PNG_COLOR_MASK_COLOR) { imgInfo.format = GL_RGB; } break; default: std::cout << "[PngDecoder] error: unknown libpng color type=" << imgInfo.color_type << " rgb=" << PNG_COLOR_TYPE_RGB << " rgba=" << PNG_COLOR_TYPE_RGBA << " palette=" << PNG_COLOR_TYPE_PALETTE << std::endl; return -1; } return 0; }
WL_EXPORT uint32_t * weston_load_image(const char *filename, int32_t *width_arg, int32_t *height_arg, uint32_t *stride_arg) { png_struct *png; png_info *info; png_byte *data; png_byte **row_pointers = NULL; png_uint_32 width, height; int depth, color_type, interlace, stride; unsigned int i; FILE *fp; fp = fopen(filename, "rb"); if (fp == NULL) return NULL; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png) { fclose(fp); return NULL; } info = png_create_info_struct(png); if (!info) { png_destroy_read_struct(&png, &info, NULL); fclose(fp); return NULL; } png_set_read_fn(png, fp, read_func); png_read_info(png, info); png_get_IHDR(png, info, &width, &height, &depth, &color_type, &interlace, NULL, NULL); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); if (color_type == PNG_COLOR_TYPE_GRAY) png_set_expand_gray_1_2_4_to_8(png); if (png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); if (depth == 16) png_set_strip_16(png); if (depth < 8) png_set_packing(png); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); if (interlace != PNG_INTERLACE_NONE) png_set_interlace_handling(png); png_set_filler(png, 0xff, PNG_FILLER_AFTER); png_set_read_user_transform_fn(png, premultiply_data); png_read_update_info(png, info); png_get_IHDR(png, info, &width, &height, &depth, &color_type, &interlace, NULL, NULL); stride = width * 4; data = malloc(stride * height); if (!data) { png_destroy_read_struct(&png, &info, NULL); fclose(fp); return NULL; } row_pointers = malloc(height * sizeof row_pointers[0]); if (row_pointers == NULL) { free(data); png_destroy_read_struct(&png, &info, NULL); fclose(fp); return NULL; } for (i = 0; i < height; i++) row_pointers[i] = &data[i * stride]; png_read_image(png, row_pointers); png_read_end(png, info); free(row_pointers); png_destroy_read_struct(&png, &info, NULL); fclose(fp); *width_arg = width; *height_arg = height; *stride_arg = stride; return (uint32_t *) data; }
static void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scaledSize, bool *doScaledRead, 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_bytep trans_alpha = 0; png_color_16p trans_color_p = 0; int num_trans; png_colorp palette = 0; int num_palette; int interlace_method; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_method, 0, 0); png_set_interlace_handling(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY) { // Black & White or 8-bit grayscale if (bit_depth == 1 && png_get_channels(png_ptr, info_ptr) == 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.setColorCount(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.setColorCount(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_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_color_p) { const int g = trans_color_p->gray; if (g < ncols) { image.setColor(g, 0); } } } } else if (color_type == PNG_COLOR_TYPE_PALETTE && png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette) && 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; } png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); image.setColorCount(num_palette); int i = 0; if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_alpha) { while (i < num_trans) { image.setColor(i, qRgba( palette[i].red, palette[i].green, palette[i].blue, trans_alpha[i] ) ); i++; } } while (i < num_palette) { image.setColor(i, qRgba( palette[i].red, palette[i].green, 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; } QSize outSize(width,height); if (!scaledSize.isEmpty() && quint32(scaledSize.width()) <= width && quint32(scaledSize.height()) <= height && interlace_method == PNG_INTERLACE_NONE) { // Do inline downscaling outSize = scaledSize; if (doScaledRead) *doScaledRead = true; } if (image.size() != outSize || image.format() != format) { image = QImage(outSize, 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); } }
pictw_t * spng_read(session_t *ps, const char *path) { assert(path); char sig[SPNG_SIGBYTES] = ""; pictw_t *pictw = NULL; png_structp png_ptr = NULL; png_infop info_ptr = NULL; FILE *fp = fopen(path, "rb"); bool need_premultiply = false; if (unlikely(!fp)) { printfef("(\"%s\"): Failed to open file.", path); goto spng_read_end; } if (unlikely(SPNG_SIGBYTES != fread(&sig, 1, SPNG_SIGBYTES, fp))) { printfef("(\"%s\"): Failed to read %d-byte signature.", path, SPNG_SIGBYTES); goto spng_read_end; } if (unlikely(png_sig_cmp((png_bytep) sig, 0, SPNG_SIGBYTES))) { printfef("(\"%s\"): PNG signature invalid.", path); goto spng_read_end; } png_ptr = allocchk(png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)); info_ptr = allocchk(png_create_info_struct(png_ptr)); if (setjmp(png_jmpbuf(png_ptr))) goto spng_read_end; png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, SPNG_SIGBYTES); png_read_info(png_ptr, info_ptr); png_uint_32 width = 0, height = 0; // Set transformations int bit_depth = 0, color_type = 0; { int interlace_type = 0; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); // Scale or strip 16-bit colors if (bit_depth == 16) { printfdf("(\"%s\"): Scaling 16-bit colors.", path); #if PNG_LIBPNG_VER >= 10504 png_set_scale_16(png_ptr); #else png_set_strip_16(png_ptr); #endif bit_depth = 8; } /* if (bit_depth < 8) png_set_packing(png_ptr); */ // No idea why this is needed... png_set_bgr(png_ptr); // Convert palette to RGB if (color_type == PNG_COLOR_TYPE_PALETTE) { printfdf("(\"%s\"): Converting palette PNG to RGB.", path); png_set_palette_to_rgb(png_ptr); color_type = PNG_COLOR_TYPE_RGB; } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { printfdf("(\"%s\"): Converting rDNS to full alpha.", path); png_set_tRNS_to_alpha(png_ptr); } if (color_type == PNG_COLOR_TYPE_GRAY || PNG_COLOR_TYPE_GRAY_ALPHA == color_type) { printfdf("(\"%s\"): Converting gray (+ alpha) PNG to RGB.", path); png_set_gray_to_rgb(png_ptr); if (PNG_COLOR_TYPE_GRAY == color_type) color_type = PNG_COLOR_TYPE_RGB; else color_type = PNG_COLOR_TYPE_RGB_ALPHA; } /* if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { printfdf("(\"%s\"): Converting 1/2/4 bit gray PNG to 8-bit.", path); #if PNG_LIBPNG_VER >= 10209 png_set_expand_gray_1_2_4_to_8(png_ptr); #else png_set_gray_1_2_4_to_8(png_ptr); #endif bit_depth = 8; } */ // Somehow XImage requires 24-bit visual to use 32 bits per pixel if (color_type == PNG_COLOR_TYPE_RGB) { printfdf("(\"%s\"): Appending filler alpha values.", path); png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); } // Premultiply alpha if (PNG_COLOR_TYPE_RGB_ALPHA == color_type) { #if PNG_LIBPNG_VER >= 10504 png_set_alpha_mode(png_ptr, PNG_ALPHA_STANDARD, 1.0); #else need_premultiply = true; #endif } /* int number_passes = 1; #ifdef PNG_READ_INTERLACING_SUPPORTED number_passes = png_set_interlace_handling(png_ptr); #endif */ if (PNG_INTERLACE_NONE != interlace_type) png_set_interlace_handling(png_ptr); } png_read_update_info(png_ptr, info_ptr); int depth = 0; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); switch (color_type) { case PNG_COLOR_TYPE_GRAY: depth = 1 * bit_depth; break; case PNG_COLOR_TYPE_RGB: depth = 3 * bit_depth; break; case PNG_COLOR_TYPE_RGB_ALPHA: depth = 4 * bit_depth; break; default: assert(0); break; } // Read data and fill to Picture { int rowbytes = png_get_rowbytes(png_ptr, info_ptr); png_bytep row_pointers[height]; memset(row_pointers, 0, sizeof(row_pointers)); row_pointers[0] = png_malloc(png_ptr, rowbytes * height); for (int row = 1; row < height; row++) row_pointers[row] = row_pointers[row - 1] + rowbytes; png_read_image(png_ptr, row_pointers); if (need_premultiply) for (int row = 0; row < height; row++) simg_data32_premultiply(row_pointers[row], width); if (unlikely(!(pictw = simg_data_to_pictw(ps, width, height, depth, row_pointers[0], rowbytes)))) { printfef("(\"%s\"): Failed to create Picture.", path); goto spng_read_end; } } spng_read_end: if (png_ptr) png_destroy_read_struct(&png_ptr, &info_ptr, NULL); if (fp) fclose(fp); return pictw; }
void load_png_buffer(std::string filename, buffer_t &buf) { png_byte header[8]; png_structp png_ptr; png_infop info_ptr; png_bytep *row_pointers; /* open file and test for it being a png */ FILE *f = fopen(filename.c_str(), "rb"); _assert(f, "File %s could not be opened for reading\n", filename.c_str()); _assert(fread(header, 1, 8, f) == 8, "File ended before end of header\n"); _assert(!png_sig_cmp(header, 0, 8), "File %s is not recognized as a PNG file\n", filename.c_str()); /* initialize stuff */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); _assert(png_ptr, "png_create_read_struct failed\n"); info_ptr = png_create_info_struct(png_ptr); _assert(info_ptr, "png_create_info_struct failed\n"); _assert(!setjmp(png_jmpbuf(png_ptr)), "Error during init_io\n"); png_init_io(png_ptr, f); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); int width = png_get_image_width(png_ptr, info_ptr); int height = png_get_image_height(png_ptr, info_ptr); int channels = png_get_channels(png_ptr, info_ptr); int bit_depth = png_get_bit_depth(png_ptr, info_ptr); // Expand low-bpp images to have only 1 pixel per byte (As opposed to tight packing) if (bit_depth < 8) { png_set_packing(png_ptr); } if (channels != 1) { buf.extent[0] = width; buf.extent[1] = height; buf.extent[2] = channels; buf.stride[0] = 1; buf.stride[1] = width; buf.stride[2] = width*height; } else { buf.extent[0] = width; buf.extent[1] = height; buf.stride[0] = 1; buf.stride[1] = width; } if (bit_depth == 8) { buf.elem_size = 1; } else { buf.elem_size = 2; } png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); // read the file _assert(!setjmp(png_jmpbuf(png_ptr)), "Error during read_image\n"); row_pointers = new png_bytep[height]; for (int y = 0; y < height; y++) { row_pointers[y] = new png_byte[png_get_rowbytes(png_ptr, info_ptr)]; } png_read_image(png_ptr, row_pointers); fclose(f); _assert((bit_depth == 8) || (bit_depth == 16), "Can only handle 8-bit or 16-bit pngs\n"); // convert the data to uint8_t int c_stride = (channels == 1) ? 0 : width*height; uint8_t *img = (uint8_t*)malloc(width*height*channels*sizeof(uint8_t)); uint8_t *ptr = img; _assert(ptr, "Error alocation memory for buffer."); if (bit_depth == 8) { for (int y = 0; y < height; y++) { uint8_t *srcPtr = (uint8_t *)(row_pointers[y]); for (int x = 0; x < width;x++) { for (int c = 0; c < channels; c++) { convert(*srcPtr++, ptr[c*c_stride]); } ptr++; } } } else if (bit_depth == 16) { for (int y = 0; y < height; y++) { uint8_t *srcPtr = (uint8_t *)(row_pointers[y]); for (int x = 0; x < width; x++) { for (int c = 0; c < channels; c++) { uint16_t hi = (*srcPtr++) << 8; uint16_t lo = hi | (*srcPtr++); convert(lo, ptr[c*c_stride]); } ptr++; } } } // Fill buffer_t buf.host = img; // clean up for (int y = 0; y < height; y++) { delete[] row_pointers[y]; } delete[] row_pointers; png_destroy_read_struct(&png_ptr, &info_ptr, NULL); buf.host_dirty = true; }
static BOOL DLL_CALLCONV Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { png_structp png_ptr; png_infop info_ptr; png_colorp palette = NULL; png_uint_32 width, height; BOOL has_alpha_channel = FALSE; RGBQUAD *pal; // pointer to dib palette int bit_depth, pixel_depth; // pixel_depth = bit_depth * channels int palette_entries; int interlace_type; fi_ioStructure fio; fio.s_handle = handle; fio.s_io = io; if ((dib) && (handle)) { try { // create the chunk manage structure png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler); if (!png_ptr) { return FALSE; } // allocate/initialize the image information data. info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return FALSE; } // Set error handling. REQUIRED if you aren't supplying your own // error handling functions in the png_create_write_struct() call. if (setjmp(png_jmpbuf(png_ptr))) { // if we get here, we had a problem reading the file png_destroy_write_struct(&png_ptr, &info_ptr); return FALSE; } // init the IO png_set_write_fn(png_ptr, &fio, _WriteProc, _FlushProc); // set physical resolution png_uint_32 res_x = (png_uint_32)FreeImage_GetDotsPerMeterX(dib); png_uint_32 res_y = (png_uint_32)FreeImage_GetDotsPerMeterY(dib); if ((res_x > 0) && (res_y > 0)) { png_set_pHYs(png_ptr, info_ptr, res_x, res_y, 1); } // Set the image information here. Width and height are up to 2^31, // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, // or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED width = FreeImage_GetWidth(dib); height = FreeImage_GetHeight(dib); pixel_depth = FreeImage_GetBPP(dib); BOOL bInterlaced = FALSE; if( (flags & PNG_INTERLACED) == PNG_INTERLACED) { interlace_type = PNG_INTERLACE_ADAM7; bInterlaced = TRUE; } else { interlace_type = PNG_INTERLACE_NONE; } // set the ZLIB compression level or default to PNG default compression level (ZLIB level = 6) int zlib_level = flags & 0x0F; if((zlib_level >= 1) && (zlib_level <= 9)) { png_set_compression_level(png_ptr, zlib_level); } else if((flags & PNG_Z_NO_COMPRESSION) == PNG_Z_NO_COMPRESSION) { png_set_compression_level(png_ptr, Z_NO_COMPRESSION); } // filtered strategy works better for high color images if(pixel_depth >= 16){ png_set_compression_strategy(png_ptr, Z_FILTERED); png_set_filter(png_ptr, 0, PNG_FILTER_NONE|PNG_FILTER_SUB|PNG_FILTER_PAETH); } else { png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY); } FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); if(image_type == FIT_BITMAP) { // standard image type bit_depth = (pixel_depth > 8) ? 8 : pixel_depth; } else { // 16-bit greyscale or 16-bit RGB(A) bit_depth = 16; } switch (FreeImage_GetColorType(dib)) { case FIC_MINISWHITE: // Invert monochrome files to have 0 as black and 1 as white (no break here) png_set_invert_mono(png_ptr); case FIC_MINISBLACK: png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_GRAY, interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); break; case FIC_PALETTE: { png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_PALETTE, interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); // set the palette palette_entries = 1 << bit_depth; palette = (png_colorp)png_malloc(png_ptr, palette_entries * sizeof (png_color)); pal = FreeImage_GetPalette(dib); for (int i = 0; i < palette_entries; i++) { palette[i].red = pal[i].rgbRed; palette[i].green = pal[i].rgbGreen; palette[i].blue = pal[i].rgbBlue; } png_set_PLTE(png_ptr, info_ptr, palette, palette_entries); // You must not free palette here, because png_set_PLTE only makes a link to // the palette that you malloced. Wait until you are about to destroy // the png structure. break; } case FIC_RGBALPHA : has_alpha_channel = TRUE; png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_RGBA, interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR // flip BGR pixels to RGB if(image_type == FIT_BITMAP) png_set_bgr(png_ptr); #endif break; case FIC_RGB: png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_RGB, interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR // flip BGR pixels to RGB if(image_type == FIT_BITMAP) png_set_bgr(png_ptr); #endif break; case FIC_CMYK: break; } // write possible ICC profile FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(dib); if (iccProfile->size && iccProfile->data) { png_set_iCCP(png_ptr, info_ptr, "Embedded Profile", 0, (png_charp)iccProfile->data, iccProfile->size); } // write metadata WriteMetadata(png_ptr, info_ptr, dib); // Optional gamma chunk is strongly suggested if you have any guess // as to the correct gamma of the image. // png_set_gAMA(png_ptr, info_ptr, gamma); // set the transparency table if ((pixel_depth == 8) && (FreeImage_IsTransparent(dib)) && (FreeImage_GetTransparencyCount(dib) > 0)) { png_set_tRNS(png_ptr, info_ptr, FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib), NULL); } // set the background color if(FreeImage_HasBackgroundColor(dib)) { png_color_16 image_background; RGBQUAD rgbBkColor; FreeImage_GetBackgroundColor(dib, &rgbBkColor); memset(&image_background, 0, sizeof(png_color_16)); image_background.blue = rgbBkColor.rgbBlue; image_background.green = rgbBkColor.rgbGreen; image_background.red = rgbBkColor.rgbRed; image_background.index = rgbBkColor.rgbReserved; png_set_bKGD(png_ptr, info_ptr, &image_background); } // Write the file header information. png_write_info(png_ptr, info_ptr); // write out the image data #ifndef FREEIMAGE_BIGENDIAN if (bit_depth == 16) { // turn on 16 bit byte swapping png_set_swap(png_ptr); } #endif int number_passes = 1; if (bInterlaced) { number_passes = png_set_interlace_handling(png_ptr); } if ((pixel_depth == 32) && (!has_alpha_channel)) { BYTE *buffer = (BYTE *)malloc(width * 3); // transparent conversion to 24-bit // the number of passes is either 1 for non-interlaced images, or 7 for interlaced images for (int pass = 0; pass < number_passes; pass++) { for (png_uint_32 k = 0; k < height; k++) { FreeImage_ConvertLine32To24(buffer, FreeImage_GetScanLine(dib, height - k - 1), width); png_write_row(png_ptr, buffer); } } free(buffer); } else { // the number of passes is either 1 for non-interlaced images, or 7 for interlaced images for (int pass = 0; pass < number_passes; pass++) { for (png_uint_32 k = 0; k < height; k++) { png_write_row(png_ptr, FreeImage_GetScanLine(dib, height - k - 1)); } } } // It is REQUIRED to call this to finish writing the rest of the file // Bug with png_flush png_write_end(png_ptr, info_ptr); // clean up after the write, and free any memory allocated if (palette) { png_free(png_ptr, palette); } png_destroy_write_struct(&png_ptr, &info_ptr); return TRUE; } catch (const char *text) { FreeImage_OutputMessageProc(s_format_id, text); } } return FALSE; }
void initialize() { // Now it's time for some transformations. if( little_endian() ) { if( this->_info._bit_depth == 16 ) { // Swap bytes of 16 bit files to least significant byte first. png_set_swap( this->get()->_struct ); } if( this->_info._bit_depth < 8 ) { // swap bits of 1, 2, 4 bit packed pixel formats png_set_packswap( this->get()->_struct ); } } if( this->_info._color_type == PNG_COLOR_TYPE_PALETTE ) { png_set_palette_to_rgb( this->get()->_struct ); } if( this->_info._num_trans > 0 ) { png_set_tRNS_to_alpha( this->get()->_struct ); } // Tell libpng to handle the gamma conversion for you. The final call // is a good guess for PC generated images, but it should be configurable // by the user at run time by the user. It is strongly suggested that // your application support gamma correction. if( this->_settings._apply_screen_gamma ) { // png_set_gamma will change the image data! #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED png_set_gamma( this->get()->_struct , this->_settings._screen_gamma , this->_info._file_gamma ); #else png_set_gamma( this->get()->_struct , this->_settings._screen_gamma , this->_info._file_gamma ); #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED } // Interlaced images are not supported. this->_number_passes = png_set_interlace_handling( this->get()->_struct ); io_error_if( this->_number_passes != 1 , "scanline_read_iterator cannot read interlaced png images." ); // The above transformation might have changed the bit_depth and color type. png_read_update_info( this->get()->_struct , this->get()->_info ); this->_info._bit_depth = png_get_bit_depth( this->get()->_struct , this->get()->_info ); this->_info._num_channels = png_get_channels( this->get()->_struct , this->get()->_info ); this->_info._color_type = png_get_color_type( this->get()->_struct , this->get()->_info ); this->_scanline_length = png_get_rowbytes( this->get()->_struct , this->get()->_info ); }
s32 pngDecSetParameter(PStream stream, PInParam in_param, POutParam out_param, PExtInParam extra_in_param = vm::null, PExtOutParam extra_out_param = vm::null) { if (in_param->outputPackFlag == CELL_PNGDEC_1BYTE_PER_NPIXEL) { fmt::throw_exception("Packing not supported! (%d)" HERE, in_param->outputPackFlag); } // flag to keep unknown chunks png_set_keep_unknown_chunks(stream->png_ptr, PNG_HANDLE_CHUNK_IF_SAFE, 0, 0); // Scale 16 bit depth down to 8 bit depth. if (stream->info.bitDepth == 16 && in_param->outputBitDepth == 8) { // PS3 uses png_set_strip_16, since png_set_scale_16 wasn't available back then. png_set_strip_16(stream->png_ptr); } // This shouldnt ever happen, but not sure what to do if it does, just want it logged for now if (stream->info.bitDepth != 16 && in_param->outputBitDepth == 16) cellPngDec.error("Output depth of 16 with non input depth of 16 specified!"); if (in_param->commandPtr != vm::null) cellPngDec.warning("Ignoring CommandPtr."); if (stream->info.colorSpace != in_param->outputColorSpace) { // check if we need to set alpha const bool inputHasAlpha = cellPngColorSpaceHasAlpha(stream->info.colorSpace); const bool outputWantsAlpha = cellPngColorSpaceHasAlpha(in_param->outputColorSpace); if (outputWantsAlpha && !inputHasAlpha) { if (in_param->outputAlphaSelect == CELL_PNGDEC_FIX_ALPHA) png_set_add_alpha(stream->png_ptr, in_param->outputColorAlpha, in_param->outputColorSpace == CELL_PNGDEC_ARGB ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER); else { // Check if we can steal the alpha from a trns block if (png_get_valid(stream->png_ptr, stream->info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(stream->png_ptr); // if not, just set default of 0xff else png_set_add_alpha(stream->png_ptr, 0xff, in_param->outputColorSpace == CELL_PNGDEC_ARGB ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER); } } else if (inputHasAlpha && !outputWantsAlpha) png_set_strip_alpha(stream->png_ptr); else if (in_param->outputColorSpace == CELL_PNGDEC_ARGB && stream->info.colorSpace == CELL_PNGDEC_RGBA) png_set_swap_alpha(stream->png_ptr); // Handle gray<->rgb colorspace conversions // rgb output if (in_param->outputColorSpace == CELL_PNGDEC_ARGB || in_param->outputColorSpace == CELL_PNGDEC_RGBA || in_param->outputColorSpace == CELL_PNGDEC_RGB) { if (stream->info.colorSpace == CELL_PNGDEC_PALETTE) png_set_palette_to_rgb(stream->png_ptr); if ((stream->info.colorSpace == CELL_PNGDEC_GRAYSCALE || stream->info.colorSpace == CELL_PNGDEC_GRAYSCALE_ALPHA) && stream->info.bitDepth < 8) png_set_expand_gray_1_2_4_to_8(stream->png_ptr); } // grayscale output else { if (stream->info.colorSpace == CELL_PNGDEC_ARGB || stream->info.colorSpace == CELL_PNGDEC_RGBA || stream->info.colorSpace == CELL_PNGDEC_RGB) { png_set_rgb_to_gray(stream->png_ptr, PNG_ERROR_ACTION_NONE, PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT); } else { // not sure what to do here cellPngDec.error("Grayscale / Palette to Grayscale / Palette conversion currently unsupported."); } } } stream->passes = png_set_interlace_handling(stream->png_ptr); // Update the info structure png_read_update_info(stream->png_ptr, stream->info_ptr); stream->out_param.outputWidth = stream->info.imageWidth; stream->out_param.outputHeight = stream->info.imageHeight; stream->out_param.outputBitDepth = in_param->outputBitDepth; stream->out_param.outputColorSpace = in_param->outputColorSpace; stream->out_param.outputMode = in_param->outputMode; stream->out_param.outputWidthByte = png_get_rowbytes(stream->png_ptr, stream->info_ptr); stream->out_param.outputComponents = png_get_channels(stream->png_ptr, stream->info_ptr); stream->packing = in_param->outputPackFlag; // Set the memory usage. We currently don't actually allocate memory for libpng through the callbacks, due to libpng needing a lot more memory compared to PS3 variant. stream->out_param.useMemorySpace = 0; if (extra_in_param) { if (extra_in_param->bufferMode != CELL_PNGDEC_LINE_MODE) { cellPngDec.error("Invalid Buffermode specified."); return CELL_PNGDEC_ERROR_ARG; } if (stream->passes > 1) { stream->outputCounts = 1; } else stream->outputCounts = extra_in_param->outputCounts; if (extra_out_param) { if (stream->outputCounts == 0) extra_out_param->outputHeight = stream->out_param.outputHeight; else extra_out_param->outputHeight = std::min(stream->outputCounts, stream->out_param.outputHeight.value()); extra_out_param->outputWidthByte = stream->out_param.outputWidthByte; } } *out_param = stream->out_param; return CELL_OK; }
void png_reader::read(unsigned x0, unsigned y0,image_data_32& image) { FILE *fp=fopen(fileName_.c_str(),"rb"); if (!fp) throw image_reader_exception("cannot open image file "+fileName_); png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,0,0,0); if (!png_ptr) { fclose(fp); throw image_reader_exception("failed to allocate png_ptr"); } // catch errors in a custom way to avoid the need for setjmp png_set_error_fn(png_ptr, png_get_error_ptr(png_ptr), user_error_fn, user_warning_fn); png_infop info_ptr; try { info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr,0,0); fclose(fp); throw image_reader_exception("failed to create info_ptr"); } } catch (std::exception const& ex) { png_destroy_read_struct(&png_ptr,0,0); fclose(fp); throw; } png_set_read_fn(png_ptr, (png_voidp)fp, png_read_data); png_read_info(png_ptr, info_ptr); if (color_type_ == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); if (color_type_ == PNG_COLOR_TYPE_GRAY && bit_depth_ < 8) png_set_expand(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); if (bit_depth_ == 16) png_set_strip_16(png_ptr); if (color_type_ == PNG_COLOR_TYPE_GRAY || color_type_ == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); // quick hack -- only work in >=libpng 1.2.7 png_set_add_alpha(png_ptr,0xff,PNG_FILLER_AFTER); //rgba double gamma; if (png_get_gAMA(png_ptr, info_ptr, &gamma)) png_set_gamma(png_ptr, 2.2, gamma); if (x0 == 0 && y0 == 0 && image.width() >= width_ && image.height() >= height_) { if (png_get_interlace_type(png_ptr,info_ptr) == PNG_INTERLACE_ADAM7) { png_set_interlace_handling(png_ptr); // FIXME: libpng bug? // according to docs png_read_image // "..automatically handles interlacing, // so you don't need to call png_set_interlace_handling()" } png_read_update_info(png_ptr, info_ptr); // we can read whole image at once // alloc row pointers boost::scoped_array<png_byte*> rows(new png_bytep[height_]); for (unsigned i=0; i<height_; ++i) rows[i] = (png_bytep)image.getRow(i); png_read_image(png_ptr, rows.get()); } else { png_read_update_info(png_ptr, info_ptr); unsigned w=std::min(unsigned(image.width()),width_); unsigned h=std::min(unsigned(image.height()),height_); unsigned rowbytes=png_get_rowbytes(png_ptr, info_ptr); boost::scoped_array<png_byte> row(new png_byte[rowbytes]); //START read image rows for (unsigned i=0;i<height_;++i) { png_read_row(png_ptr,row.get(),0); if (i>=y0 && i<h) { image.setRow(i-y0,reinterpret_cast<unsigned*>(&row[x0]),w); } } //END } png_read_end(png_ptr,0); png_destroy_read_struct(&png_ptr, &info_ptr,0); fclose(fp); }
pngquant_error rwpng_read_image24_libpng(struct rwpng_data * read_data, png24_image *mainprog_ptr) { png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_size_t rowbytes; int color_type, bit_depth; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, mainprog_ptr, rwpng_error_handler, NULL); if (!png_ptr) { return PNG_OUT_OF_MEMORY_ERROR; /* out of memory */ } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); return PNG_OUT_OF_MEMORY_ERROR; /* out of memory */ } /* setjmp() must be called in every function that calls a non-trivial * libpng function */ if (setjmp(mainprog_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return LIBPNG_FATAL_ERROR; /* fatal libpng error (via longjmp()) */ } //struct rwpng_data read_data = {infile, 0,}; png_set_read_fn(png_ptr, read_data, user_read_data); png_read_info(png_ptr, info_ptr); /* read all PNG info up to image data */ /* alternatively, could make separate calls to png_get_image_width(), * etc., but want bit_depth and color_type for later [don't care about * compression_type and filter_type => NULLs] */ png_get_IHDR(png_ptr, info_ptr, &mainprog_ptr->width, &mainprog_ptr->height, &bit_depth, &color_type, NULL, NULL, NULL); /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits, * transparency chunks to full alpha channel; strip 16-bit-per-sample * images to 8 bits per sample; and convert grayscale to RGB[A] */ /* GRR TO DO: preserve all safe-to-copy ancillary PNG chunks */ if (!(color_type & PNG_COLOR_MASK_ALPHA)) { #ifdef PNG_READ_FILLER_SUPPORTED /* GRP: expand palette to RGB, and grayscale or RGB to GA or RGBA */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); png_set_filler(png_ptr, 65535L, PNG_FILLER_AFTER); #else fprintf(stderr, "pngquant readpng: image is neither RGBA nor GA\n"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); mainprog_ptr->retval = 26; return mainprog_ptr->retval; #endif } /* if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); */ if (bit_depth == 16) png_set_strip_16(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); /* get and save the gamma info (if any) for writing */ double gamma; mainprog_ptr->gamma = png_get_gAMA(png_ptr, info_ptr, &gamma) ? gamma : 0.45455; png_set_interlace_handling(png_ptr); /* all transformations have been registered; now update info_ptr data, * get rowbytes and channels, and allocate image memory */ png_read_update_info(png_ptr, info_ptr); rowbytes = png_get_rowbytes(png_ptr, info_ptr); if ((mainprog_ptr->rgba_data = malloc(rowbytes*mainprog_ptr->height)) == NULL) { fprintf(stderr, "pngquant readpng: unable to allocate image data\n"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return PNG_OUT_OF_MEMORY_ERROR; } png_bytepp row_pointers = rwpng_create_row_pointers(info_ptr, png_ptr, mainprog_ptr->rgba_data, mainprog_ptr->height, 0); /* now we can go ahead and just read the whole image */ png_read_image(png_ptr, row_pointers); /* and we're done! (png_read_end() can be omitted if no processing of * post-IDAT text/time/etc. is desired) */ png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); mainprog_ptr->file_size = read_data->bytes_read; mainprog_ptr->row_pointers = (unsigned char **)row_pointers; return SUCCESS; }
/** Reads one PNG file. @param process Process the image data (0 for initial parameter determination) @returns -1 on failure, 1 on sucess */ int decode_png(const char *pngname, int process, parameters_t *param) { int num_pass = 1; int bit_depth, color_type; FILE *pngfile; //png_byte hdptr[8]; /* Now open this PNG file, and examine its header to retrieve the YUV4MPEG info that shall be written */ pngfile = fopen(pngname, "rb"); if (!pngfile) { perror("PNG file open failed:"); return -1; } //fread(hdptr, 1, 8, pngfile); #if 0 bool is_png = !png_sig_cmp(hdptr, 0, 8); if (!is_png) { mjpeg_error("%s is _no_ PNG file !\n"); return -1; } #endif png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) mjpeg_error_exit1("%s: Could not allocate PNG read struct !", pngname); png_init_io(png_ptr, pngfile); //png_set_sig_bytes(png_ptr, 8); info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); mjpeg_error_exit1("%s: Could not allocate PNG info struct !", pngname); } end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); mjpeg_error_exit1("%s: Could not allocate PNG end info struct !", pngname); } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); mjpeg_error("%s: Corrupted PNG file !", pngname); return -1; } if (process) png_set_read_user_transform_fn(png_ptr, png_separation); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_STRIP_ALPHA, NULL); if (png_get_IHDR(png_ptr, info_ptr, ¶m->width, ¶m->height, &bit_depth, // &color_type, &interlace_type, &compression_type, &filter_type)) &color_type, NULL, NULL, NULL)) num_pass = png_set_interlace_handling(png_ptr); else mjpeg_error_exit1("PNG header reading failed !!\n"); #if 0 mjpeg_info("Reading info struct...\n"); png_read_info(png_ptr, info_ptr); mjpeg_info("Done...\n"); if (png_get_IHDR(png_ptr, info_ptr, ¶m->width, ¶m->height, &bit_depth, // &color_type, &interlace_type, &compression_type, &filter_type)) &color_type, NULL, NULL, NULL)) num_pass = png_set_interlace_handling(png_ptr); else mjpeg_error_exit1("PNG header reading failed !!\n"); if (process) { printf("%d passes needed\n\n", num_pass); if (bit_depth != 8 && bit_depth != 16) { mjpeg_error_exit1("Invalid bit_depth %d, only 8 and 16 bit allowed !!\n", bit_depth); } png_set_strip_16(png_ptr); // always has to strip the 16bit input, MPEG can't handle it png_set_strip_alpha(png_ptr); // Alpha can't be processed until Z/Alpha is integrated printf("\nAllocating row buffer..."); png_set_read_user_transform_fn(png_ptr, png_separation); png_bytep row_buf = (png_bytep)png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); for (int n=0; n < num_pass; n++) for (int y=0; y < sh_param->height; y++) { printf("Writing row data for pass %d\n", n); png_read_rows(png_ptr, (png_bytepp)&row_buf, NULL, 1); } png_free(png_ptr, row_buf); } png_read_end(png_ptr, info_ptr); #endif if (setjmp(png_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return 2; } fclose(pngfile); return 1; }
PyObject* _png_module::_read_png(const Py::Object& py_fileobj, const bool float_result) { png_byte header[8]; // 8 is the maximum size that can be checked FILE* fp = NULL; bool close_file = false; #if PY3K int fd = PyObject_AsFileDescriptor(py_fileobj.ptr()); PyErr_Clear(); #endif if (py_fileobj.isString()) { std::string fileName = Py::String(py_fileobj); const char *file_name = fileName.c_str(); if ((fp = fopen(file_name, "rb")) == NULL) { throw Py::RuntimeError( Printf("Could not open file %s for reading", file_name).str()); } close_file = true; } #if PY3K else if (fd != -1) { fp = fdopen(fd, "r"); } #else else if (PyFile_CheckExact(py_fileobj.ptr())) { fp = PyFile_AsFile(py_fileobj.ptr()); } #endif else { PyObject* read_method = PyObject_GetAttrString(py_fileobj.ptr(), "read"); if (!(read_method && PyCallable_Check(read_method))) { Py_XDECREF(read_method); throw Py::TypeError("Object does not appear to be a 8-bit string path or a Python file-like object"); } Py_XDECREF(read_method); } if (fp) { if (fread(header, 1, 8, fp) != 8) { throw Py::RuntimeError( "_image_module::readpng: error reading PNG header"); } } else { _read_png_data(py_fileobj.ptr(), header, 8); } if (png_sig_cmp(header, 0, 8)) { throw Py::RuntimeError( "_image_module::readpng: file not recognized as a PNG file"); } /* initialize stuff */ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { throw Py::RuntimeError( "_image_module::readpng: png_create_read_struct failed"); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { throw Py::RuntimeError( "_image_module::readpng: png_create_info_struct failed"); } if (setjmp(png_jmpbuf(png_ptr))) { throw Py::RuntimeError( "_image_module::readpng: error during init_io"); } if (fp) { png_init_io(png_ptr, fp); } else { png_set_read_fn(png_ptr, (void*)py_fileobj.ptr(), &read_png_data); } png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); png_uint_32 width = png_get_image_width(png_ptr, info_ptr); png_uint_32 height = png_get_image_height(png_ptr, info_ptr); int bit_depth = png_get_bit_depth(png_ptr, info_ptr); // Unpack 1, 2, and 4-bit images if (bit_depth < 8) png_set_packing(png_ptr); // If sig bits are set, shift data png_color_8p sig_bit; if ((png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_PALETTE) && png_get_sBIT(png_ptr, info_ptr, &sig_bit)) { png_set_shift(png_ptr, sig_bit); } // Convert big endian to little if (bit_depth == 16) { png_set_swap(png_ptr); } // Convert palletes to full RGB if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } // If there's an alpha channel convert gray to RGB if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); } png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); /* read file */ if (setjmp(png_jmpbuf(png_ptr))) { throw Py::RuntimeError( "_image_module::readpng: error during read_image"); } png_bytep *row_pointers = new png_bytep[height]; png_uint_32 row; for (row = 0; row < height; row++) { row_pointers[row] = new png_byte[png_get_rowbytes(png_ptr,info_ptr)]; } png_read_image(png_ptr, row_pointers); npy_intp dimensions[3]; dimensions[0] = height; //numrows dimensions[1] = width; //numcols if (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_ALPHA) { dimensions[2] = 4; //RGBA images } else if (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_COLOR) { dimensions[2] = 3; //RGB images } else { dimensions[2] = 1; //Greyscale images } //For gray, return an x by y array, not an x by y by 1 int num_dims = (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_COLOR) ? 3 : 2; PyArrayObject *A = NULL; if (float_result) { double max_value = (1 << ((bit_depth < 8) ? 8 : bit_depth)) - 1; A = (PyArrayObject *) PyArray_SimpleNew(num_dims, dimensions, NPY_FLOAT); if (A == NULL) { throw Py::MemoryError("Could not allocate image array"); } for (png_uint_32 y = 0; y < height; y++) { png_byte* row = row_pointers[y]; for (png_uint_32 x = 0; x < width; x++) { size_t offset = y * A->strides[0] + x * A->strides[1]; if (bit_depth == 16) { png_uint_16* ptr = &reinterpret_cast<png_uint_16*>(row)[x * dimensions[2]]; for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) { *(float*)(A->data + offset + p*A->strides[2]) = (float)(ptr[p]) / max_value; } } else { png_byte* ptr = &(row[x * dimensions[2]]); for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) { *(float*)(A->data + offset + p*A->strides[2]) = (float)(ptr[p]) / max_value; } } } } } else { A = (PyArrayObject *) PyArray_SimpleNew(num_dims, dimensions, NPY_UBYTE); if (A == NULL) { throw Py::MemoryError("Could not allocate image array"); } for (png_uint_32 y = 0; y < height; y++) { png_byte* row = row_pointers[y]; for (png_uint_32 x = 0; x < width; x++) { size_t offset = y * A->strides[0] + x * A->strides[1]; if (bit_depth == 16) { png_uint_16* ptr = &reinterpret_cast<png_uint_16*>(row)[x * dimensions[2]]; for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) { *(png_byte*)(A->data + offset + p*A->strides[2]) = ptr[p] >> 8; } } else { png_byte* ptr = &(row[x * dimensions[2]]); for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) { *(png_byte*)(A->data + offset + p*A->strides[2]) = ptr[p]; } } } }
int fh_png_load(const char *name, unsigned char *buffer, int x, int y) { static const png_color_16 my_background = {0, 0, 0, 0, 0}; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; unsigned int i; int bit_depth, color_type, interlace_type; int number_passes, pass; png_byte * fbptr; FILE * fh; if (!(fh = fopen(name, "rb"))) return(FH_ERROR_FILE); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) return(FH_ERROR_FORMAT); info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); fclose(fh); return(FH_ERROR_FORMAT); } if (setjmp(png_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fh); return(FH_ERROR_FORMAT); } png_init_io(png_ptr, fh); png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); png_set_background(png_ptr, (png_color_16 *)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); /* other possibility for png_set_background: use png_get_bKGD */ } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); png_set_background(png_ptr, (png_color_16 *)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); } if (color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); /* on Intel PC ?: if (bit_depth == 16) png_set_swap(png_ptr); */ number_passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); if (width * 3 != png_get_rowbytes(png_ptr, info_ptr)) { printf("[png.cpp]: Error processing %s - please report (including image).\n", name); return(FH_ERROR_FORMAT); } for(pass = 0; pass < number_passes; pass++) { fbptr = (png_byte *)buffer; for (i = 0; i < height; i++, fbptr += width * 3) { png_read_row(png_ptr, fbptr, NULL); } } png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fh); return(FH_ERROR_OK); }