// Copy of HdTrueColorOsd::OpenPngFile() // expected image returned should be RGBA bool png_file_2_rgb(char const *path, Byte **&rows, int &width, int &height) { Byte header[8]; FILE *fp = fopen(path, "rb"); if (!fp || fread(header, 1, 8, fp) != 8) { if(fp) fclose(fp); return false; } if (png_sig_cmp(header, 0, 8)) { fclose(fp); return false; } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fclose(fp); return false; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); fclose(fp); return false; } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fp); return false; } png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); if (setjmp(png_jmpbuf(png_ptr))) { ::printf("setjmp err\n"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return false; } png_read_info(png_ptr, info_ptr); png_byte h = info_ptr->height; png_byte color_type = info_ptr->color_type; #define PRINT_COLOR_TYPE 1 #ifdef PRINT_COLOR_TYPE png_byte w = info_ptr->width; png_byte bit_depth = info_ptr->bit_depth; printf("bit depth: %i - ", bit_depth); switch (color_type) { case PNG_COLOR_TYPE_GRAY: puts("color_type: PNG_COLOR_TYPE_GRAY"); break; case PNG_COLOR_TYPE_PALETTE: puts("color_type: PNG_COLOR_TYPE_PALETTE"); break; case PNG_COLOR_TYPE_RGB: puts("color_type: PNG_COLOR_TYPE_RGB"); break; case PNG_COLOR_TYPE_RGB_ALPHA: puts("color_type: PNG_COLOR_TYPE_RGB_ALPHA"); break; case PNG_COLOR_TYPE_GRAY_ALPHA: puts("color_type: PNG_COLOR_TYPE_GRAY_ALPHA"); break; default: puts("ERROR: unknown color_type"); break; } #endif if (color_type == PNG_COLOR_TYPE_PALETTE) // Lets have RGB { png_set_expand(png_ptr); png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER); } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER); png_read_update_info(png_ptr, info_ptr); rows = (png_bytep*) malloc(sizeof(png_bytep) * h); int y; for (y=0; y<h; y++) { rows[y] = (png_byte*) malloc(info_ptr->rowbytes); } png_read_image(png_ptr, rows); width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return true; } // png_file_2_rgb()
Texture *PNGReader::readImage() { char header[8]; FILE *fp = fopen(m_filename, "rb"); if(!fp) { printf("PNGReader: Problem reading %s\n", m_filename); exit(1); } fread(header, 1, 8, fp); if(png_sig_cmp((unsigned char*)header, 0, 8)) { printf("PNGReader: %s not a png file\n", m_filename); exit(1); } // Initialization png_structp png_pointer = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png_infop png_info_pointer = png_create_info_struct(png_pointer); png_init_io(png_pointer, fp); png_set_sig_bytes(png_pointer, 8); png_read_info(png_pointer, png_info_pointer); int width = png_get_image_width(png_pointer, png_info_pointer); int height = png_get_image_height(png_pointer, png_info_pointer); png_byte colour_type = png_get_color_type(png_pointer, png_info_pointer); png_byte bit_depth = png_get_bit_depth(png_pointer, png_info_pointer); printf("Image %s width %d height %d colour_type", m_filename, width, height); print_colour_type(colour_type); printf(" bit depth %d\n", bit_depth); int number_of_passes = png_set_interlace_handling(png_pointer); png_read_update_info(png_pointer, png_info_pointer); int image_channels; switch(colour_type) { case PNG_COLOR_TYPE_RGB: image_channels = 3; break; default: printf("PNGReader Error: Image not RGB\n"); exit(1); } // Read unsigned char *data = (unsigned char*) malloc (sizeof(unsigned char)*height*width*image_channels+1); png_bytep row_pointers[height]; unsigned int rowBytes = png_get_rowbytes(png_pointer, png_info_pointer); for(int i = 0; i < height; i ++) { row_pointers[i] = data + ((height-(i+1))*rowBytes); } png_read_image(png_pointer, row_pointers); png_read_end(png_pointer, NULL); /* * Image seems to get image upside-down. With RGB backwards. */ Texture *input = new Texture(width, height, Image::RGB, (char*)data); input->toBMP("test_out.bmp"); return input; }
static PyObject *_read_png(PyObject *filein, bool float_result) { png_byte header[8]; // 8 is the maximum size that can be checked FILE *fp = NULL; mpl_off_t offset = 0; bool close_file = false; bool close_dup_file = false; PyObject *py_file = NULL; png_structp png_ptr = NULL; png_infop info_ptr = NULL; int num_dims; std::vector<png_bytep> row_pointers; png_uint_32 width = 0; png_uint_32 height = 0; int bit_depth; PyObject *result = NULL; // TODO: Remove direct calls to Numpy API here if (PyBytes_Check(filein) || PyUnicode_Check(filein)) { if ((py_file = mpl_PyFile_OpenFile(filein, (char *)"rb")) == NULL) { goto exit; } close_file = true; } else { py_file = filein; } if ((fp = mpl_PyFile_Dup(py_file, (char *)"rb", &offset))) { close_dup_file = true; } else { PyErr_Clear(); PyObject *read_method = PyObject_GetAttrString(py_file, "read"); if (!(read_method && PyCallable_Check(read_method))) { Py_XDECREF(read_method); PyErr_SetString(PyExc_TypeError, "Object does not appear to be a 8-bit string path or " "a Python file-like object"); goto exit; } Py_XDECREF(read_method); } if (fp) { if (fread(header, 1, 8, fp) != 8) { PyErr_SetString(PyExc_IOError, "error reading PNG header"); goto exit; } } else { _read_png_data(py_file, header, 8); } if (png_sig_cmp(header, 0, 8)) { PyErr_SetString(PyExc_ValueError, "invalid PNG header"); goto exit; } /* initialize stuff */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { PyErr_SetString(PyExc_RuntimeError, "png_create_read_struct failed"); goto exit; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { PyErr_SetString(PyExc_RuntimeError, "png_create_info_struct failed"); goto exit; } if (setjmp(png_jmpbuf(png_ptr))) { PyErr_SetString(PyExc_RuntimeError, "Error setting jump"); goto exit; } if (fp) { png_init_io(png_ptr, fp); } else { png_set_read_fn(png_ptr, (void *)py_file, &read_png_data); } 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); 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); bit_depth = 8; } // 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); row_pointers.resize(height); for (png_uint_32 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[0]); 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 } if (float_result) { double max_value = (1 << bit_depth) - 1; numpy::array_view<float, 3> A(dimensions); for (png_uint_32 y = 0; y < height; y++) { png_byte *row = row_pointers[y]; for (png_uint_32 x = 0; x < width; x++) { 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++) { A(y, x, p) = (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++) { A(y, x, p) = (float)(ptr[p]) / max_value; } } } } result = A.pyobj(); } else if (bit_depth == 16) { numpy::array_view<png_uint_16, 3> A(dimensions); for (png_uint_32 y = 0; y < height; y++) { png_byte *row = row_pointers[y]; for (png_uint_32 x = 0; x < width; x++) { 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++) { A(y, x, p) = ptr[p]; } } } result = A.pyobj(); } else if (bit_depth == 8) { numpy::array_view<png_byte, 3> A(dimensions); for (png_uint_32 y = 0; y < height; y++) { png_byte *row = row_pointers[y]; for (png_uint_32 x = 0; x < width; x++) { png_byte *ptr = &(row[x * dimensions[2]]); for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) { A(y, x, p) = ptr[p]; } } } result = A.pyobj(); } else { PyErr_SetString(PyExc_RuntimeError, "image has unknown bit depth"); goto exit; } // free the png memory png_read_end(png_ptr, info_ptr); // For gray, return an x by y array, not an x by y by 1 num_dims = (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_COLOR) ? 3 : 2; if (num_dims == 2) { PyArray_Dims dims = {dimensions, 2}; PyObject *reshaped = PyArray_Newshape((PyArrayObject *)result, &dims, NPY_CORDER); Py_DECREF(result); result = reshaped; } exit: if (png_ptr && info_ptr) { #ifndef png_infopp_NULL png_destroy_read_struct(&png_ptr, &info_ptr, NULL); #else png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); #endif } if (close_dup_file) { mpl_PyFile_DupClose(py_file, fp, offset); } if (close_file) { mpl_PyFile_CloseFile(py_file); Py_DECREF(py_file); } for (png_uint_32 row = 0; row < height; row++) { delete[] row_pointers[row]; } if (PyErr_Occurred()) { Py_XDECREF(result); return NULL; } else { return result; } }
int main ( int argc, char** argv) { FILE* fp; size_t width = 0; size_t height = 0; size_t depth = 0; size_t channels = 0; size_t r; /* counter for rows */ PNGImage* image; if ( argc < 2 ) { usage( argv[0] ); exit(1); } image = readPNGfile(argv[1]); if ( image == NULL ) { exit(1); } /* Retrive basic image information */ width = png_get_image_width( image->png, image->info ); height = png_get_image_height( image->png, image->info ); depth = png_get_bit_depth( image->png, image->info ); channels = png_get_channels( image->png, image->info ); printf("Image Info:\nWidth :%d\nHeight :%d\nBit depth:%d\n", width, height, depth ); printf("Channels :%u\n", channels); printf("Creating info file\n"); /*-------------------------------------------*/ fp = fopen("info","wb"); if (!fp) { printf("Could not create info file\n"); png_destroy_read_struct( &image->png, &image->info, &image->end); exit(1); } fwrite(image->info, sizeof(png_info), 1,fp ); fclose(fp); printf("Creating end file\n"); /*-------------------------------------------*/ fp = fopen("end","wb"); if (!fp) { printf("Could not create end file\n"); png_destroy_read_struct( &image->png, &image->info, &image->end); exit(1); } fwrite(image->end, sizeof(png_info), 1,fp ); fclose(fp); printf("Creating raw file\n"); /*-------------------------------------------*/ fp = fopen("raw","wb"); if (!fp) { printf("Could not create raw file\n"); png_destroy_read_struct( &image->png, &image->info, &image->end); exit(1); } for ( r=0; r < height; r = r+1 ) fwrite(image->row_pointers[r], sizeof(png_byte), width, fp ); fclose(fp); printf("Releasing memory\n"); png_destroy_read_struct( &image->png, &image->info, &image->end); return 0; }
uint8_t* ImageDecoder::decodePNGImpl(png_structp pngPtr, uint32_t* width, uint32_t* height) { png_bytep* rowPtrs = NULL; uint8_t* outData = NULL; png_infop infoPtr = png_create_info_struct(pngPtr); if (!infoPtr) { LOG(LOG_ERROR,"Couldn't initialize png info struct"); png_destroy_read_struct(&pngPtr, (png_infopp)0, (png_infopp)0); return NULL; } if (setjmp(png_jmpbuf(pngPtr))) { png_destroy_read_struct(&pngPtr, &infoPtr,(png_infopp)0); if (rowPtrs != NULL) delete [] rowPtrs; if (outData != NULL) delete outData; LOG(LOG_ERROR,"error during reading of the png file"); return NULL; } png_read_info(pngPtr, infoPtr); *width = png_get_image_width(pngPtr, infoPtr); *height = png_get_image_height(pngPtr, infoPtr); //bits per CHANNEL! note: not per pixel! png_uint_32 bitdepth = png_get_bit_depth(pngPtr, infoPtr); //Number of channels png_uint_32 channels = png_get_channels(pngPtr, infoPtr); //Color type. (RGB, RGBA, Luminance, luminance alpha... palette... etc) png_uint_32 color_type = png_get_color_type(pngPtr, infoPtr); switch (color_type) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(pngPtr); channels = 3; break; case PNG_COLOR_TYPE_GRAY: if (bitdepth < 8) png_set_gray_to_rgb(pngPtr); bitdepth = 8; break; } rowPtrs = new png_bytep[(*height)]; outData = new uint8_t[(*width) * (*height) * bitdepth * channels / 8]; const unsigned int stride = (*width) * bitdepth * channels / 8; for (size_t i = 0; i < (*height); i++) { rowPtrs[i] = (png_bytep)outData + i* stride; } png_read_image(pngPtr, rowPtrs); delete[] (png_bytep)rowPtrs; png_destroy_read_struct(&pngPtr, &infoPtr,(png_infopp)0); return outData; }
static uint8_t png_read( png_structp readPtr, png_image * image, uint32_t flags ) { // png_set_error_fn( readPtr, NULL, png_user_error, NULL ); png_infop infoPtr = png_create_info_struct( readPtr ); if (!infoPtr) { pngio_error( "Couldn't initialize PNG info struct." ); png_destroy_read_struct( & readPtr, NULL, NULL ); return 0; } if (setjmp( png_jmpbuf( readPtr ) )) { pngio_error( "An error occured while reading the PNG file." ); png_destroy_read_struct( & readPtr, & infoPtr, NULL ); png_image_free( image ); return 0; } png_set_sig_bytes( readPtr, 8 ); #ifdef PNG_APPLE_MODE_SUPPORTED if (png_get_apple_mode()) { png_set_keep_unknown_chunks( readPtr, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0 ); png_set_read_user_chunk_fn( readPtr, NULL, png_read_user_chunk ); } #endif png_read_info( readPtr, infoPtr ); png_uint_32 w = png_get_image_width( readPtr, infoPtr ); png_uint_32 h = png_get_image_height( readPtr, infoPtr ); png_uint_32 bitDepth = png_get_bit_depth( readPtr, infoPtr ); png_uint_32 channels = png_get_channels( readPtr, infoPtr ); png_uint_32 interlaceType = png_get_interlace_type( readPtr, infoPtr ); png_uint_32 colorType = png_get_color_type( readPtr, infoPtr ); switch (colorType) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb( readPtr ); channels = 3; break; case PNG_COLOR_TYPE_GRAY: if (bitDepth < 8) { png_set_expand_gray_1_2_4_to_8( readPtr ); bitDepth = 8; } png_set_gray_to_rgb( readPtr ); break; } if (png_get_valid( readPtr, infoPtr, PNG_INFO_tRNS )) { png_set_tRNS_to_alpha( readPtr ); channels += 1; } else if (!(colorType & PNG_COLOR_MASK_ALPHA)) { png_set_add_alpha( readPtr, 0xff, PNG_FILLER_AFTER ); } if (bitDepth == 16) { png_set_strip_16( readPtr ); } #ifdef PNG_APPLE_MODE_SUPPORTED if (png_get_apple_mode()) { if (flags & PNG_IMAGE_PREMULTIPLY_ALPHA) { png_set_read_user_transform_fn( readPtr, png_read_swap_transform ); } else { png_set_read_user_transform_fn( readPtr, png_read_swap_and_unpremultiply_transform ); } png_set_user_transform_info( readPtr, NULL, bitDepth, channels ); png_read_update_info( readPtr, infoPtr ); } else #endif { if (flags & PNG_IMAGE_PREMULTIPLY_ALPHA) { png_set_read_user_transform_fn( readPtr, png_read_premultiply_transform ); } } png_image_alloc( image, w, h ); png_bytep p = image->data; const size_t passCount = interlaceType == PNG_INTERLACE_NONE ? 1 : png_set_interlace_handling( readPtr ); const size_t bytesPerRow = w * 4; if (flags & PNG_IMAGE_FLIP_VERTICAL) { for (size_t pass = 0; pass < passCount; pass++) { for (size_t i = 0; i < h; i++) { png_read_row( readPtr, p + (bytesPerRow * (h - i - 1)), NULL ); } } } else { // png_bytep rp[h]; // for (size_t i = 0; i < h; i++) // { // rp[i] = p + (bytesPerRow * i); // } // png_read_image( readPtr, rp ); for (size_t pass = 0; pass < passCount; pass++) { for (size_t i = 0; i < h; i++) { png_read_row( readPtr, p + (bytesPerRow * i), NULL ); } } } png_destroy_read_struct( & readPtr, & infoPtr, NULL ); return 1; }
BOOL CImage::LoadBitmapFromPNGFile(LPTSTR szFileName) { BOOL bStatus = FALSE; FILE *fp = NULL; const int number = 8; png_byte header[number]; png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_infop end_info = NULL; png_uint_32 rowbytes = 0; png_uint_32 width = 0; png_uint_32 height = 0; png_bytep row = NULL; int y = 0; BITMAPINFO* pBMI = NULL; HDC hDC = NULL; _TFOPEN_S(fp, szFileName, _T("rb")); if (!fp) { return FALSE; } fread(header, 1, number, fp); if(png_sig_cmp(header, 0, number)) { goto cleanup; } png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) goto cleanup; if (setjmp(png_ptr->jmpbuf)) goto cleanup; info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) goto cleanup; end_info = png_create_info_struct(png_ptr); if (!end_info) goto cleanup; png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, number); // Read PNG information png_read_info(png_ptr, info_ptr); // Get count of bytes per row rowbytes = png_get_rowbytes(png_ptr, info_ptr); row = new png_byte[rowbytes]; width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); if(info_ptr->channels==3) { png_set_strip_16(png_ptr); png_set_packing(png_ptr); png_set_bgr(png_ptr); } hDC = GetDC(NULL); { CAutoLock lock(&m_csLock); if(m_bLoadCancelled) goto cleanup; m_hBitmap = CreateCompatibleBitmap(hDC, width, height); } pBMI = (BITMAPINFO*)new BYTE[sizeof(BITMAPINFO)+256*4]; memset(pBMI, 0, sizeof(BITMAPINFO)+256*4); pBMI->bmiHeader.biSize = sizeof(BITMAPINFO); pBMI->bmiHeader.biBitCount = 8*info_ptr->channels; pBMI->bmiHeader.biWidth = width; pBMI->bmiHeader.biHeight = height; pBMI->bmiHeader.biPlanes = 1; pBMI->bmiHeader.biCompression = BI_RGB; pBMI->bmiHeader.biSizeImage = rowbytes*height; if( info_ptr->channels == 1 ) { RGBQUAD* palette = pBMI->bmiColors; int i; for( i = 0; i < 256; i++ ) { palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i; palette[i].rgbReserved = 0; } palette[256].rgbBlue = palette[256].rgbGreen = palette[256].rgbRed = 255; } for(y=height-1; y>=0; y--) { png_read_rows(png_ptr, &row, png_bytepp_NULL, 1); { CAutoLock lock(&m_csLock); int n = SetDIBits(hDC, m_hBitmap, y, 1, row, pBMI, DIB_RGB_COLORS); if(n==0) goto cleanup; } } /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); bStatus = TRUE; cleanup: if(fp!=NULL) { fclose(fp); } if(png_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)&info_ptr, (png_infopp)&end_info); } if(row) { delete [] row; } if(pBMI) { delete [] pBMI; } if(!bStatus) { Destroy(); } return bStatus; }
struct PNG read_png_file(char *filename) { unsigned char header[8]; // 8 is the maximum size that can be checked /* open file and test for it being a png */ FILE *fp = fopen(filename, "rb"); if (!fp) { abort_("[read_png_file] File %s could not be opened for reading", filename); } 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", filename); } /* initialize stuff */ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { abort_("[read_png_file] png_create_read_struct failed"); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { abort_("[read_png_file] png_create_info_struct failed"); } if (setjmp(png_jmpbuf(png_ptr))) { abort_("[read_png_file] Error during init_io"); } png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); struct PNG png; png.width = png_get_image_width(png_ptr, info_ptr); png.height = png_get_image_height(png_ptr, info_ptr); png_byte color_type = png_get_color_type(png_ptr, info_ptr); png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr); if (color_type != PNG_COLOR_TYPE_RGB && color_type != PNG_COLOR_TYPE_RGB_ALPHA) { abort_("[read_png_file] PNG %s must be RGB or RGBA", filename); } if (bit_depth != 8) { abort_("[read_png_file] PNG %s must be 8 bits per channel", filename); } if (color_type == PNG_COLOR_TYPE_RGB) { png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER); } png_read_update_info(png_ptr, info_ptr); /* read file */ if (setjmp(png_jmpbuf(png_ptr))) { abort_("[read_png_file] Error during read_image"); } png.row_pointers = (png_bytep *)malloc(sizeof(png_bytep) * png.height); int row_size = png.width * 4; int y; for (y = 0; y < png.height; y++) { png.row_pointers[y] = (png_byte *)malloc(row_size); } png_read_image(png_ptr, png.row_pointers); png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fp); return png; }
// TODO: clean up error handling, too much dupe code right now bool PNG::_read_file(string const & file_name) { // unfortunately, we need to break down to the C-code level here, since // libpng is written in C itself // we need to open the file in binary mode FILE * fp = fopen(file_name.c_str(), "rb"); if (!fp) { epng_err("Failed to open " + file_name); return false; } // read in the header (max size of 8), use it to validate this as a PNG file png_byte header[8]; fread(header, 1, 8, fp); if (png_sig_cmp(header, 0, 8)) { epng_err("File is not a valid PNG file"); fclose(fp); _init(); return false; } // set up libpng structs for reading info png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { epng_err("Failed to create read struct"); fclose(fp); _init(); return false; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { epng_err("Failed to create info struct"); png_destroy_read_struct(&png_ptr, NULL, NULL); fclose(fp); _init(); return false; } // set error handling to not abort the entire program if (setjmp(png_jmpbuf(png_ptr))) { epng_err("Error initializing libpng io"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); _init(); return false; } // initialize png reading png_init_io(png_ptr, fp); // let it know we've already read the first 8 bytes png_set_sig_bytes(png_ptr, 8); // read in the basic image info png_read_info(png_ptr, info_ptr); // convert to 8 bits png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); // verify this is in RGBA format, and if not, convert it to RGBA png_byte color_type = png_get_color_type(png_ptr, info_ptr); if (color_type != PNG_COLOR_TYPE_RGBA && color_type != PNG_COLOR_TYPE_RGB) { if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (bit_depth < 8) png_set_expand(png_ptr); png_set_gray_to_rgb(png_ptr); } if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); } // convert tRNS to alpha channel if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); _width = png_get_image_width(png_ptr, info_ptr); _height = png_get_image_height(png_ptr, info_ptr); png_read_update_info(png_ptr, info_ptr); // begin reading in the image if (setjmp(png_jmpbuf(png_ptr))) { epng_err("Error reading image with libpng"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); _init(); return false; } int bpr = png_get_rowbytes(png_ptr, info_ptr); // number of bytes in a row int numchannels = png_get_channels(png_ptr, info_ptr); // initialie our image storage _pixels = new RGBAPixel[_height * _width]; png_byte * row = new png_byte[bpr]; for (int y = 0; y < _height; y++) { png_read_row(png_ptr, row, NULL); png_byte * pix = row; for (int x = 0; x < _width; x++) { RGBAPixel & pixel = _pixel(x,y); if (numchannels == 1 || numchannels == 2) { // monochrome unsigned char color = (unsigned char) *pix++; pixel.red = color; pixel.green = color; pixel.blue = color; if (numchannels == 2) pixel.alpha = (unsigned char) *pix++; else pixel.alpha = 255; } else if (numchannels == 3 || numchannels == 4) { pixel.red = (unsigned char) *pix++; pixel.green = (unsigned char) *pix++; pixel.blue = (unsigned char) *pix++; if (numchannels == 4) pixel.alpha = (unsigned char) *pix++; else pixel.alpha = 255; } } } // cleanup delete [] row; png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return true; }
int ReadTextureFromPNG( struct Texture * t, const char * filename ) { #ifdef USE_PNG png_structp png_ptr; png_infop info_ptr; int number_of_passes; png_bytep* row_pointers; png_byte color_type; png_byte bit_depth; unsigned x; int r; unsigned char header[8]; // 8 is the maximum size that can be checked FILE * fp = fopen( filename, "rb" ); //open file and test for it being a png if (!fp) { fprintf( stderr, "[read_png_file] File %s could not be opened for reading", filename ); goto quickexit; } r = fread(header, 8, 1, fp); if (png_sig_cmp(header, 0, 8)) { fprintf( stderr, "[read_png_file] File %s is not recognized as a PNG file", filename ); goto closeandquit; } //initialize stuff png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fprintf( stderr, "[read_png_file] png_create_read_struct failed"); goto closeandquit; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { fprintf( stderr, "[read_png_file] png_create_info_struct failed"); goto closepngandquit; } if (setjmp(png_jmpbuf(png_ptr))) { fprintf( stderr, "[read_png_file] Error during init_io"); goto closepngandquit; } png_set_sig_bytes(png_ptr, 8); png_set_read_fn( png_ptr, fp, mypngreadfn ); png_read_info(png_ptr, info_ptr); t->width = png_get_image_width(png_ptr, info_ptr); t->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); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); number_of_passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); // read file if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr,"[read_png_file] Error during read_image"); goto closepngandquit; } row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * t->height); unsigned int y; for ( y=0; y < (unsigned)t->height; y++) row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr, info_ptr)); png_read_image(png_ptr, row_pointers); png_read_end( png_ptr, info_ptr ); png_destroy_read_struct( &png_ptr, &info_ptr, NULL ); png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); if (color_type & PNG_COLOR_MASK_COLOR ) if (color_type & PNG_COLOR_MASK_ALPHA) t->format = TTRGBA; else t->format = TTRGB; else if (color_type & PNG_COLOR_MASK_ALPHA) t->format = TTGRAYALPHA; else t->format = TTGRAYSCALE; // SAFE_DELETE(texture->m_data); t->rawdata = malloc( t->width * t->height * channels[t->format] ); switch (t->format) { case TTGRAYSCALE: for ( y=0; y < (unsigned)t->height; ++y) { png_byte* row = row_pointers[y]; for ( x = 0; x < t->width; ++x) { png_byte* ptr = &(row[x]); t->rawdata[(x + y * t->width)] = ptr[0]; } } break; case TTGRAYALPHA: for ( y=0; y < (unsigned)t->height; ++y) { png_byte* row = row_pointers[y]; for ( x = 0; x < t->width; ++x) { png_byte* ptr = &(row[x*2]); t->rawdata[(x + y * t->width) * 2] = ptr[0]; t->rawdata[(x + y * t->width) * 2 + 1] = ptr[1]; } } break; case TTRGBA: for ( y=0; y < (unsigned)t->height; ++y) { png_byte* row = row_pointers[y]; for ( x = 0; x < t->width; ++x) { png_byte* ptr = &(row[x*4]); t->rawdata[(x + y * t->width) * 4] = ptr[0]; t->rawdata[(x + y * t->width) * 4 + 1] = ptr[1]; t->rawdata[(x + y * t->width) * 4 + 2] = ptr[2]; t->rawdata[(x + y * t->width) * 4 + 3] = ptr[3]; } } break; case TTRGB: for ( y=0; y < (unsigned)t->height; y++) { png_byte* row = row_pointers[y]; for (x=0; x<t->width; x++) { png_byte* ptr = &(row[x * 3]); t->rawdata[(x + y * t->width) * 3] = ptr[0]; t->rawdata[(x + y * t->width) * 3 + 1] = ptr[1]; t->rawdata[(x + y * t->width) * 3 + 2] = ptr[2]; } } break; default: fprintf( stderr, "Warning: Invalid color byte type for PNG."); break; } for ( y=0; y < (unsigned)t->height; y++) free(row_pointers[y]); free(row_pointers); t->type = GL_TEXTURE_2D; return 0; closepngandquit: png_read_end( png_ptr, info_ptr ); png_destroy_read_struct( &png_ptr, &info_ptr, NULL ); png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); closeandquit: fclose( fp ); quickexit: return -1; #else fprintf( stderr, "Error. Cannot load: %s. PNG Support not included.\n" ); return -1; #endif }