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; // size_t rowbytes; png_infop info; png_structp png; png_bytep *row_pointers; byte *data; byte *out; // int size; // load png ri.FS_ReadFile( name, ( void ** ) &data ); if ( !data ) { return; } //png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png = png_create_read_struct( PNG_LIBPNG_VER_STRING, ( png_voidp ) NULL, 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 ) NULL, ( png_infopp ) NULL ); 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 ) NULL ); return; } //png_set_write_fn(png, buffer, png_write_data, png_flush_data); 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, NULL, NULL, NULL ); // 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 //if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) // png_set_gray_1_2_4_to_8(png); // 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 ); } // 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 ) NULL ); return; } //rowbytes = png_get_rowbytes(png, info); 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 ) NULL ); ri.Hunk_FreeTempMemory( row_pointers ); ri.FS_FreeFile( data ); }
bool ImageLoaderPNG::ReadData() { const int kNumSigBytesToRead = 8; uint8 pngSigBuf[kNumSigBytesToRead]; memcpy(pngSigBuf, m_RawData, kNumSigBytesToRead); const int numSigNoMatch = png_sig_cmp(pngSigBuf, 0, kNumSigBytesToRead); if(numSigNoMatch) { ReportError("Incorrect PNG signature"); return false; } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png_ptr) { ReportError("Could not create read struct"); return false; } png_infop info_ptr = png_create_info_struct(png_ptr); if(!info_ptr) { ReportError("Could not create info struct"); png_destroy_read_struct(&png_ptr, NULL, NULL); return false; } // Read from our buffer, not a file pointer... png_set_read_fn(png_ptr, this, PNGStreamReader::ReadDataFromStream); // Make sure to tell libpng how many bytes we've read... png_set_sig_bytes(png_ptr, kNumSigBytesToRead); png_read_info(png_ptr, info_ptr); int bitDepth = 0; int colorType = -1; if( 1 != png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *)(&m_Width), (png_uint_32 *)(&m_Height), &bitDepth, &colorType, NULL, NULL, NULL) ) { ReportError("Could not read PNG header"); png_destroy_read_struct(&png_ptr, NULL, NULL); return false; } if(bitDepth != 8) { ReportError("Only 8-bit images currently supported."); png_destroy_read_struct(&png_ptr, NULL, NULL); return false; } const int numPixels = m_Width * m_Height; png_size_t bpr = png_get_rowbytes(png_ptr, info_ptr); png_bytep rowData = new png_byte[bpr]; switch(colorType) { default: ReportError("PNG color type unsupported"); png_destroy_read_struct(&png_ptr, NULL, NULL); delete [] rowData; return false; case PNG_COLOR_TYPE_PALETTE: { m_RedChannelPrecision = bitDepth; m_RedData = new unsigned char[numPixels]; m_GreenChannelPrecision = bitDepth; m_GreenData = new unsigned char[numPixels]; m_BlueChannelPrecision = bitDepth; m_BlueData = new unsigned char[numPixels]; png_colorp palette; int nPaletteEntries; png_uint_32 ret = png_get_PLTE(png_ptr, info_ptr, &palette, &nPaletteEntries); if(ret != PNG_INFO_PLTE) { memset(m_BlueData, 0, numPixels); memset(m_RedData, 0, numPixels); memset(m_GreenData, 0, numPixels); assert(!"Couldn't find PLTE chunk"); break; } for(uint32 i = 0; i < m_Height; i++) { png_read_row(png_ptr, rowData, NULL); unsigned int rowOffset = i * m_Width; for(uint32 j = 0; j < m_Width; j++) { assert(rowData[j] < nPaletteEntries); const png_color &c = palette[::std::min<unsigned char>(rowData[j], nPaletteEntries - 1)]; m_RedData[rowOffset + j] = c.red; m_GreenData[rowOffset + j] = c.green; m_BlueData[rowOffset + j] = c.blue; } } } break; case PNG_COLOR_TYPE_GRAY: { m_RedChannelPrecision = bitDepth; m_RedData = new unsigned char[numPixels]; m_GreenChannelPrecision = bitDepth; m_GreenData = new unsigned char[numPixels]; m_BlueChannelPrecision = bitDepth; m_BlueData = new unsigned char[numPixels]; for(uint32 i = 0; i < m_Height; i++) { png_read_row(png_ptr, rowData, NULL); unsigned int rowOffset = i * m_Width; unsigned int byteIdx = 0; for(uint32 j = 0; j < m_Width; j++) { m_RedData[rowOffset + j] = rowData[byteIdx]; m_GreenData[rowOffset + j] = rowData[byteIdx]; m_BlueData[rowOffset + j] = rowData[byteIdx]; byteIdx++; } assert(byteIdx == bpr); } } break; case PNG_COLOR_TYPE_RGB: m_RedChannelPrecision = bitDepth; m_RedData = new unsigned char[numPixels]; m_GreenChannelPrecision = bitDepth; m_GreenData = new unsigned char[numPixels]; m_BlueChannelPrecision = bitDepth; m_BlueData = new unsigned char[numPixels]; for(uint32 i = 0; i < m_Height; i++) { png_read_row(png_ptr, rowData, NULL); unsigned int rowOffset = i * m_Width; unsigned int byteIdx = 0; for(uint32 j = 0; j < m_Width; j++) { m_RedData[rowOffset + j] = rowData[byteIdx++]; m_GreenData[rowOffset + j] = rowData[byteIdx++]; m_BlueData[rowOffset + j] = rowData[byteIdx++]; } assert(byteIdx == bpr); } break; case PNG_COLOR_TYPE_RGB_ALPHA: m_RedChannelPrecision = bitDepth; m_RedData = new unsigned char[numPixels]; m_GreenChannelPrecision = bitDepth; m_GreenData = new unsigned char[numPixels]; m_BlueChannelPrecision = bitDepth; m_BlueData = new unsigned char[numPixels]; m_AlphaChannelPrecision = bitDepth; m_AlphaData = new unsigned char[numPixels]; for(uint32 i = 0; i < m_Height; i++) { png_read_row(png_ptr, rowData, NULL); unsigned int rowOffset = i * m_Width; unsigned int byteIdx = 0; for(uint32 j = 0; j < m_Width; j++) { m_RedData[rowOffset + j] = rowData[byteIdx++]; m_GreenData[rowOffset + j] = rowData[byteIdx++]; m_BlueData[rowOffset + j] = rowData[byteIdx++]; m_AlphaData[rowOffset + j] = rowData[byteIdx++]; } assert(byteIdx == bpr); } break; case PNG_COLOR_TYPE_GRAY_ALPHA: m_RedChannelPrecision = bitDepth; m_RedData = new unsigned char[numPixels]; m_AlphaChannelPrecision = bitDepth; m_AlphaData = new unsigned char[numPixels]; for(uint32 i = 0; i < m_Height; i++) { png_read_row(png_ptr, rowData, NULL); unsigned int rowOffset = i * m_Width; unsigned int byteIdx = 0; for(uint32 j = 0; j < m_Width; j++) { m_RedData[rowOffset + j] = rowData[byteIdx++]; m_AlphaData[rowOffset + j] = rowData[byteIdx++]; } assert(byteIdx == bpr); } break; } // Cleanup delete [] rowData; png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return true; }
/* This routine is based in part on the Chapter 13 demo code in "PNG: The * Definitive Guide" (http://www.cdrom.com/pub/png/pngbook.html). */ BGD_DECLARE(gdImagePtr) gdImageCreateFromPngCtx (gdIOCtx * infile) { png_byte sig[8]; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height, rowbytes; int bit_depth, color_type, interlace_type; int num_palette, num_trans; png_colorp palette; png_color_16p trans_gray_rgb; png_color_16p trans_color_rgb; png_bytep trans; png_bytep image_data = NULL; png_bytepp row_pointers = NULL; gdImagePtr im = NULL; int i, j, *open = NULL; volatile int transparent = -1; volatile int palette_allocated = FALSE; /* Make sure the signature can't match by dumb luck -- TBB */ /* GRR: isn't sizeof(infile) equal to the size of the pointer? */ memset (infile, 0, sizeof (infile)); /* first do a quick check that the file really is a PNG image; could * have used slightly more general png_sig_cmp() function instead */ gdGetBuf (sig, 8, infile); if (!png_check_sig (sig, 8)) return NULL; /* bad signature */ #ifndef PNG_SETJMP_NOT_SUPPORTED png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, &gdPngJmpbufStruct, gdPngErrorHandler, NULL); #else png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); #endif if (png_ptr == NULL) { fprintf (stderr, "gd-png error: cannot allocate libpng main struct\n"); return NULL; } info_ptr = png_create_info_struct (png_ptr); if (info_ptr == NULL) { fprintf (stderr, "gd-png error: cannot allocate libpng info struct\n"); png_destroy_read_struct (&png_ptr, NULL, NULL); return NULL; } /* we could create a second info struct here (end_info), but it's only * useful if we want to keep pre- and post-IDAT chunk info separated * (mainly for PNG-aware image editors and converters) */ /* setjmp() must be called in every non-callback function that calls a * PNG-reading libpng function */ #ifndef PNG_SETJMP_NOT_SUPPORTED if (setjmp (gdPngJmpbufStruct.jmpbuf)) { fprintf (stderr, "gd-png error: setjmp returns error condition\n"); png_destroy_read_struct (&png_ptr, &info_ptr, NULL); return NULL; } #endif png_set_sig_bytes (png_ptr, 8); /* we already read the 8 signature bytes */ png_set_read_fn (png_ptr, (void *) infile, gdPngReadData); png_read_info (png_ptr, info_ptr); /* read all PNG info up to image data */ png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); if ((color_type == PNG_COLOR_TYPE_RGB) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA)) { im = gdImageCreateTrueColor ((int) width, (int) height); } else { im = gdImageCreate ((int) width, (int) height); } if (im == NULL) { fprintf (stderr, "gd-png error: cannot allocate gdImage struct\n"); png_destroy_read_struct (&png_ptr, &info_ptr, NULL); gdFree (image_data); gdFree (row_pointers); return NULL; } if (bit_depth == 16) png_set_strip_16 (png_ptr); else if (bit_depth < 8) png_set_packing (png_ptr); /* expand to 1 byte per pixel */ switch (color_type) { case PNG_COLOR_TYPE_PALETTE: png_get_PLTE (png_ptr, info_ptr, &palette, &num_palette); #ifdef DEBUG fprintf (stderr, "gd-png color_type is palette, colors: %d\n", num_palette); #endif /* DEBUG */ if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) { /* gd 2.0: we support this rather thoroughly now. Grab the first fully transparent entry, if any, as the value of the simple-transparency index, mostly for backwards binary compatibility. The alpha channel is where it's really at these days. */ int firstZero = 1; png_get_tRNS (png_ptr, info_ptr, &trans, &num_trans, NULL); for (i = 0; i < num_trans; ++i) { im->alpha[i] = gdAlphaMax - (trans[i] >> 1); if ((trans[i] == 0) && (firstZero)) { /* 2.0.5: long-forgotten patch from Wez Furlong */ transparent = i; firstZero = 0; } } } break; case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_GRAY_ALPHA: /* create a fake palette and check for single-shade transparency */ if ((palette = (png_colorp) gdMalloc (256 * sizeof (png_color))) == NULL) { fprintf (stderr, "gd-png error: cannot allocate gray palette\n"); png_destroy_read_struct (&png_ptr, &info_ptr, NULL); return NULL; } palette_allocated = TRUE; if (bit_depth < 8) { num_palette = 1 << bit_depth; for (i = 0; i < 256; ++i) { j = (255 * i) / (num_palette - 1); palette[i].red = palette[i].green = palette[i].blue = j; } } else { num_palette = 256; for (i = 0; i < 256; ++i) { palette[i].red = palette[i].green = palette[i].blue = i; } } if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) { png_get_tRNS (png_ptr, info_ptr, NULL, NULL, &trans_gray_rgb); if (bit_depth == 16) /* png_set_strip_16() not yet in effect */ transparent = trans_gray_rgb->gray >> 8; else transparent = trans_gray_rgb->gray; /* Note slight error in 16-bit case: up to 256 16-bit shades * may get mapped to a single 8-bit shade, and only one of them * is supposed to be transparent. IOW, both opaque pixels and * transparent pixels will be mapped into the transparent entry. * There is no particularly good way around this in the case * that all 256 8-bit shades are used, but one could write some * custom 16-bit code to handle the case where there are gdFree * palette entries. This error will be extremely rare in * general, though. (Quite possibly there is only one such * image in existence.) */ } break; case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: /* gd 2.0: we now support truecolor. See the comment above for a rare situation in which the transparent pixel may not work properly with 16-bit channels. */ if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) { png_get_tRNS (png_ptr, info_ptr, NULL, NULL, &trans_color_rgb); if (bit_depth == 16) /* png_set_strip_16() not yet in effect */ transparent = gdTrueColor (trans_color_rgb->red >> 8, trans_color_rgb->green >> 8, trans_color_rgb->blue >> 8); else transparent = gdTrueColor (trans_color_rgb->red, trans_color_rgb->green, trans_color_rgb->blue); }
int res_create_surface_png(const char* name, gr_surface* pSurface) { GGLSurface* surface = NULL; int result = 0; unsigned char header[8]; png_structp png_ptr = NULL; png_infop info_ptr = NULL; FILE* fp = fopen(name, "rb"); if (fp == NULL) { char resPath[256]; if (gr_get_rotation() % 180 == 0) snprintf(resPath, sizeof(resPath)-1, "/res/portrait/%s.png", name); else snprintf(resPath, sizeof(resPath)-1, "/res/landscape/%s.png", name); resPath[sizeof(resPath)-1] = '\0'; fp = fopen(resPath, "rb"); if (fp == NULL) { result = -1; goto exit; } } size_t bytesRead = fread(header, 1, sizeof(header), fp); if (bytesRead != sizeof(header)) { result = -2; goto exit; } if (png_sig_cmp(header, 0, sizeof(header))) { result = -3; goto exit; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { result = -4; goto exit; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { result = -5; goto exit; } if (setjmp(png_jmpbuf(png_ptr))) { result = -6; goto exit; } png_set_packing(png_ptr); png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, sizeof(header)); png_read_info(png_ptr, info_ptr); size_t width = info_ptr->width; size_t height = info_ptr->height; size_t stride = 4 * width; size_t pixelSize = stride * height; int color_type = info_ptr->color_type; int bit_depth = info_ptr->bit_depth; int channels = info_ptr->channels; if (!(bit_depth == 8 && ((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) || (channels == 4 && color_type == PNG_COLOR_TYPE_RGBA) || (channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE)))) { result = -7; goto exit; } surface = malloc(sizeof(GGLSurface) + pixelSize); if (surface == NULL) { result = -8; goto exit; } unsigned char* pData = (unsigned char*) (surface + 1); surface->version = sizeof(GGLSurface); surface->width = width; surface->height = height; surface->stride = width; /* Yes, pixels, not bytes */ surface->data = pData; surface->format = (channels == 3) ? GGL_PIXEL_FORMAT_RGBX_8888 : GGL_PIXEL_FORMAT_RGBA_8888; if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } int y; if (channels < 4) { for (y = 0; y < (int) height; ++y) { unsigned char* pRow = pData + y * stride; png_read_row(png_ptr, pRow, NULL); int x; for(x = width - 1; x >= 0; x--) { int sx = x * 3; int dx = x * 4; unsigned char r = pRow[sx]; unsigned char g = pRow[sx + 1]; unsigned char b = pRow[sx + 2]; unsigned char a = 0xff; pRow[dx ] = r; // r pRow[dx + 1] = g; // g pRow[dx + 2] = b; // b pRow[dx + 3] = a; } } } else { for (y = 0; y < (int) height; ++y) { unsigned char* pRow = pData + y * stride; png_read_row(png_ptr, pRow, NULL); } } *pSurface = (gr_surface) surface; exit: png_destroy_read_struct(&png_ptr, &info_ptr, NULL); if (fp != NULL) { fclose(fp); } if (result < 0) { if (surface) { free(surface); } } return result; }
bool ImageLoader::ReadPNG(ImageLoaderParams &ImgInfo) { // Set up libpng reading. png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, PNGErrorFn, PNGWarnFn); if (!png_ptr) return false; png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); 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); return false; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return false; } // We read using a FILE*; this could be changed. File::IOFile file; if (!file.Open(ImgInfo.Path, "rb")) { return false; } png_init_io(png_ptr, file.GetHandle()); png_set_sig_bytes(png_ptr, 0); // Process PNG header, etc. png_read_info(png_ptr, info_ptr); png_uint_32 width, height; int bit_depth, color_type, interlace_type, compression_type, filter_method; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_method); // Force RGB (8 or 16-bit). if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); // Force 8-bit RGB. if (bit_depth == 16) png_set_strip_16(png_ptr); // Force alpha channel (combined with the above, 8-bit RGBA). if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); else if ((color_type & PNG_COLOR_MASK_ALPHA) == 0) png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER); png_read_update_info(png_ptr, info_ptr); ImgInfo.Width = width; ImgInfo.Height = height; ImgInfo.data_size = width * height * 4; ImgInfo.dst = ImgInfo.request_buffer_delegate(ImgInfo.data_size, false); std::vector<u8*> row_pointers(height); u8* row_pointer = ImgInfo.dst; for (unsigned i = 0; i < height; ++i) { row_pointers[i] = row_pointer; row_pointer += width * 4; } png_read_image(png_ptr, row_pointers.data()); png_read_end(png_ptr, end_info); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return true; }
RawImage* ImageFactory::loadPNG(const char *filename) { int outWidth, outHeight; bool outHasAlpha; png_structp png_ptr; png_infop info_ptr; unsigned int sig_read = 0; int color_type, interlace_type; FILE* fp = fopen(filename, "rb"); if (fp == NULL) return NULL; /* Create and initialize the png_struct * with the desired error handler * functions. If you want to use the * default stderr and longjump method, * you can supply NULL for the last * three parameters. We also supply the * the compiler header file version, so * that we know if the application * was compiled with a compatible version * of the library. REQUIRED */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fclose(fp); return NULL; } /* Allocate/initialize the memory * for image information. REQUIRED. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(fp); png_destroy_read_struct(&png_ptr, NULL, NULL); return NULL; } /* Set error handling if you are * using the setjmp/longjmp method * (this is the normal method of * doing things with libpng). * REQUIRED unless you set up * your own error handlers in * the png_create_read_struct() * earlier. */ if (setjmp(png_jmpbuf(png_ptr))) { /* Free all of the memory associated * with the png_ptr and info_ptr */ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); /* If we get here, we had a * problem reading the file */ return NULL; } /* Set up the output control if * you are using standard C streams */ png_init_io(png_ptr, fp); /* If we have already * read some of the signature */ png_set_sig_bytes(png_ptr, sig_read); /* * If you have enough memory to read * in the entire image at once, and * you need to specify only * transforms that can be controlled * with one of the PNG_TRANSFORM_* * bits (this presently excludes * dithering, filling, setting * background, and doing gamma * adjustment), then you can read the * entire image (including pixels) * into the info structure with this * call * * PNG_TRANSFORM_STRIP_16 | * PNG_TRANSFORM_PACKING forces 8 bit * PNG_TRANSFORM_EXPAND forces to * expand a palette into RGB */ png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL); png_uint_32 width, height; int bit_depth; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); outWidth = width; outHeight = height; switch (color_type) { case PNG_COLOR_TYPE_RGBA: outHasAlpha = true; break; case PNG_COLOR_TYPE_RGB: outHasAlpha = false; break; default: printf("Color type %d not supported.", color_type); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return NULL; } unsigned int row_bytes = png_get_rowbytes(png_ptr, info_ptr); //*outData = (unsigned char*) malloc(row_bytes * outHeight); GLubyte *outData = (unsigned char*) malloc(row_bytes * outHeight); png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr); for (int i = 0; i < outHeight; i++) { // note that png is ordered top to // bottom, but OpenGL expect it bottom to top // so the order or swapped memcpy(outData+(row_bytes * (outHeight-1-i)), row_pointers[i], row_bytes); } /* Clean up after the read, * and free any memory allocated */ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); /* Close the file */ fclose(fp); /* That's it */ return new RawImage(outWidth, outHeight, outHasAlpha, outData); }
BMGError ReadPNGInfo( const char *filename, struct BMGImageStruct * volatile img ) { jmp_buf err_jmp; int error; FILE * volatile file = NULL; int BitDepth; int ColorType; int InterlaceType; unsigned char signature[8]; png_structp volatile png_ptr = NULL; png_infop volatile info_ptr = NULL; png_infop volatile end_info = NULL; png_uint_32 Width, Height; /* error handler */ error = setjmp( err_jmp ); if (error != 0) { if (end_info != NULL) png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info); else if (info_ptr != NULL) png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, NULL); else if (png_ptr != NULL) png_destroy_read_struct((png_structp *) &png_ptr, NULL, NULL); if (img) FreeBMGImage(img); if (file) fclose(file); SetLastBMGError((BMGError) error); return (BMGError) error; } if ( img == NULL ) longjmp ( err_jmp, (int)errInvalidBMGImage ); file = fopen( filename, "rb" ); if ( !file || fread( signature, 1, 8, file ) != 8) longjmp ( err_jmp, (int)errFileOpen ); /* check the signature */ if ( png_sig_cmp( signature, 0, 8 ) != 0 ) longjmp( err_jmp, (int)errUnsupportedFileFormat ); /* create a pointer to the png read structure */ png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); if ( !png_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create a pointer to the png info structure */ info_ptr = png_create_info_struct( png_ptr ); if ( !info_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create a pointer to the png end-info structure */ end_info = png_create_info_struct(png_ptr); if (!end_info) longjmp( err_jmp, (int)errMemoryAllocation ); /* bamboozle the PNG longjmp buffer */ /*generic PNG error handler*/ /* error will always == 1 which == errLib */ // error = png_setjmp(png_ptr); error = setjmp( png_jmpbuf( png_ptr ) ); if ( error > 0 ) longjmp( err_jmp, error ); /* set function pointers in the PNG library, for read callbacks */ png_set_read_fn(png_ptr, (png_voidp) file, user_read_data); /*let the read functions know that we have already read the 1st 8 bytes */ png_set_sig_bytes( png_ptr, 8 ); /* read all PNG data up to the image data */ png_read_info( png_ptr, info_ptr ); /* extract the data we need to form the HBITMAP from the PNG header */ png_get_IHDR( png_ptr, info_ptr, &Width, &Height, &BitDepth, &ColorType, &InterlaceType, NULL, NULL); img->width = (unsigned int) Width; img->height = (unsigned int) Height; img->bits_per_pixel = (unsigned char)32; img->scan_width = Width * 4; img->palette_size = (unsigned short)0; img->bytes_per_palette_entry = 4U; img->bits = NULL; png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info); fclose( file ); return BMG_OK; }
int read_png_file(uint8_t *data[ 4 ], int linesize[ 4 ], int *width, int *height, enum AVPixelFormat *pix_fmt, const char *filename, void *log_ctx) { png_structp png_ptr; png_infop info_ptr; int number_of_passes; png_bytep *row_pointers; png_bytep image_data; png_byte color_type; png_byte bit_depth; char header[ 8 ]; int rowbytes; int res = 0; FILE *fp = fopen(filename,"rb"); if (! fp) return -1; while (true) { fread(header,1,8,fp); if (png_sig_cmp(header,0,8)) { res = -1; break; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); if (! png_ptr) { res = -1; break; } info_ptr = png_create_info_struct(png_ptr); if (! info_ptr) { res = -1; break; } if (setjmp(png_jmpbuf(png_ptr))) { res = -1; break; } 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); *pix_fmt = AV_PIX_FMT_RGBA; 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); if (setjmp(png_jmpbuf(png_ptr))) { res = -1; break; } rowbytes = png_get_rowbytes(png_ptr,info_ptr); image_data = (png_bytep) malloc(rowbytes * *height); row_pointers = (png_bytep *) malloc(sizeof(png_bytep) * *height); int y; for (y = 0; y < *height; y++) { row_pointers[ y ] = image_data + (y * rowbytes); } png_read_image(png_ptr,row_pointers); data[ 0 ] = image_data; data[ 1 ] = 0; data[ 2 ] = 0; data[ 3 ] = 0; linesize[ 0 ] = rowbytes; linesize[ 1 ] = 0; linesize[ 2 ] = 0; linesize[ 3 ] = 0; break; } fclose(fp); return res; }
image_t *load_png(char *png) { int width = 0; int height = 0; FILE *f = NULL; png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_infop end_info = NULL; png_uint_32 rowbytes = 0; image_t *image = NULL; f = open_png(png); if (f == NULL) goto err; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, NULL, NULL); if (!png_ptr) goto err; info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) goto err; end_info = png_create_info_struct(png_ptr); if (!end_info) goto err; if (setjmp(png_jmpbuf(png_ptr))) { printf("[read_png_file] Error during read_image"); goto err; } png_init_io(png_ptr, f); png_set_sig_bytes(png_ptr, HEADER_SIZE); png_read_info(png_ptr, info_ptr); rowbytes = png_get_rowbytes(png_ptr, info_ptr); width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); if (png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_RGBA) { printf("Error: PNG format is not RGBA\n"); goto err; } if (setjmp(png_jmpbuf(png_ptr))) { printf("[read_png_file] Error during read_image"); goto err; } image = make_image(width, height, rowbytes); if (image == NULL) goto err; png_read_image(png_ptr, image->rows); png_read_end(png_ptr, end_info); done: if (f != NULL) fclose(f); if (png_ptr != NULL) png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return image; err: free_image(image); image = NULL; goto done; }
/* create a new finfo record, open FITS file */ static Finfo FinfoNew(char *fname) { int len; char *e=NULL; char *f=NULL; char *s=NULL; #if FITS2PNG int i; unsigned char header[8]; /* use volatile to make gcc [-Wclobbered] happy (because of setjmp below) */ volatile Finfo finfo; #else Finfo finfo; #endif /* sanity check */ if( !fname ) return NULL; /* return existing finfo, if possible */ if( (finfo=FinfoLookup(fname)) ) return finfo; /* allocate record */ if( !(finfo = (Finfo)xcalloc(sizeof(FinfoRec), 1)) ){ fprintf(stderr, "ERROR: can't allocate rec for image\n"); return NULL; } /* save file name */ finfo->fname = xstrdup(fname); /* check for file type */ if( (s = strrchr(fname, '.')) && !strcasecmp(s, ".png") ){ /* its a PNG */ finfo->ftype = FTYPE_PNG; } else { /* assume FITS type */ finfo->ftype = FTYPE_FITS; } /* open file */ switch(finfo->ftype){ case FTYPE_PNG: #if FITS2PNG /* code taken from "PNG: The Definitive Guide" by Greg Roelofs, Chapter 13 "Reading PNG Images" */ /* set data path */ datapath = getenv("JS9_DATAPATH"); /* look for path of the PNG file */ s = Find(fname, "r", NULL, datapath); if( s && *s ){ if( !(finfo->fp = fopen(s, "rb")) ){ fprintf(stderr, "ERROR: can't open PNG file '%s'\n", fname); goto error; } fread(header, 1, 8, finfo->fp); if( png_sig_cmp(header, 0, 8) ){ fprintf(stderr, "ERROR: not recognized as a PNG file '%s'\n", fname); goto error; } /* initialize stuff */ finfo->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if( !finfo->png_ptr ){ fprintf(stderr, "ERROR: png_create_read_struct failed '%s'\n", fname); goto error; } finfo->info_ptr = png_create_info_struct(finfo->png_ptr); if( !finfo->info_ptr ){ fprintf(stderr, "ERROR: png_create_info_struct failed '%s'\n", fname); goto error; } if( setjmp(png_jmpbuf(finfo->png_ptr)) ){ fprintf(stderr, "ERROR: during png init_io '%s'\n", fname); goto error; } png_init_io(finfo->png_ptr, finfo->fp); png_set_sig_bytes(finfo->png_ptr, 8); png_read_info(finfo->png_ptr, finfo->info_ptr); /* get the text chunks that come before the image */ if( png_get_text(finfo->png_ptr, finfo->info_ptr, &(finfo->text_ptr), &(finfo->num_text)) > 0 ){ /* process all known PNG keywords */ for(i=0; i<finfo->num_text; i++){ if( !strcmp(finfo->text_ptr[i].key, FITSFILE) ){ finfo->fitsfile = xstrdup(finfo->text_ptr[i].text); /* remove the extension that was used to generate png */ s = strchr(finfo->fitsfile, '['); if( s ){ *s = '\0'; } } } } } else { fprintf(stderr, "ERROR: can't find PNG file '%s' [data path: %s]\n", fname, datapath?datapath:"none"); goto error; } #else fprintf(stderr, "ERROR: for fits2png support, build JS9 using --with-png\n"); goto error; #endif break; /* look for an error */ case FTYPE_FITS: /* fits file can have an extension */ f = FileRoot(fname); /* set data path */ datapath = getenv("JS9_DATAPATH"); /* look for path of the FITS file */ s = Find(f, "r", NULL, datapath); xfree(f); if( s && *s ){ len = strlen(s) + 1; /* construct full path to fits file + extension */ e = FileExtension(fname); if( e ){ len += strlen(e); } finfo->fitsfile = xmalloc(len); strcpy(finfo->fitsfile, s); if( e ){ strcat(finfo->fitsfile, e); } xfree(s); } else { fprintf(stderr, "ERROR: can't find FITS file '%s' [data path: %s]\n", fname, datapath?datapath:"none"); goto error; } break; default: fprintf(stderr, "ERROR: unknown file type '%s'\n", fname); goto error; break; } /* add this finfo to end of list of existing finfos */ FinfoListAdd(&finfohead, finfo); /* return the news */ return finfo; error: /* free up struct and return nothing */ _FinfoFree(finfo); return NULL; }
bool CGLCG::loadPngImage(const TCHAR *name, int &outWidth, int &outHeight, bool &outHasAlpha, GLubyte **outData) { png_structp png_ptr; png_infop info_ptr; unsigned int sig_read = 0; int color_type, interlace_type; FILE *fp; if ((fp = _tfopen(name, TEXT("rb"))) == NULL) return false; /* Create and initialize the png_struct * with the desired error handler * functions. If you want to use the * default stderr and longjump method, * you can supply NULL for the last * three parameters. We also supply the * the compiler header file version, so * that we know if the application * was compiled with a compatible version * of the library. REQUIRED */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fclose(fp); return false; } /* Allocate/initialize the memory * for image information. REQUIRED. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(fp); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return false; } /* Set error handling if you are * using the setjmp/longjmp method * (this is the normal method of * doing things with libpng). * REQUIRED unless you set up * your own error handlers in * the png_create_read_struct() * earlier. */ if (setjmp(png_jmpbuf(png_ptr))) { /* Free all of the memory associated * with the png_ptr and info_ptr */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fp); /* If we get here, we had a * problem reading the file */ return false; } /* Set up the output control if * you are using standard C streams */ png_init_io(png_ptr, fp); /* If we have already * read some of the signature */ png_set_sig_bytes(png_ptr, sig_read); /* * If you have enough memory to read * in the entire image at once, and * you need to specify only * transforms that can be controlled * with one of the PNG_TRANSFORM_* * bits (this presently excludes * dithering, filling, setting * background, and doing gamma * adjustment), then you can read the * entire image (including pixels) * into the info structure with this * call * * PNG_TRANSFORM_STRIP_16 | * PNG_TRANSFORM_PACKING forces 8 bit * PNG_TRANSFORM_EXPAND forces to * expand a palette into RGB */ png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, (png_voidp)NULL); outWidth = png_get_image_width(png_ptr, info_ptr); outHeight = png_get_image_height(png_ptr, info_ptr); switch (png_get_color_type(png_ptr, info_ptr)) { case PNG_COLOR_TYPE_RGBA: outHasAlpha = true; break; case PNG_COLOR_TYPE_RGB: outHasAlpha = false; break; default: png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return false; } unsigned int row_bytes = png_get_rowbytes(png_ptr, info_ptr); *outData = (unsigned char*) malloc(row_bytes * outHeight); png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr); for (int i = 0; i < outHeight; i++) { memcpy(*outData+(row_bytes * i), row_pointers[i], row_bytes); } /* Clean up after the read, * and free any memory allocated */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); /* Close the file */ fclose(fp); /* That's it */ return true; }
void Texture::InitWithFile(string& filepath) { FILE* fd = FileIO::OpenFileDescriptor(filepath); png_byte header[8]; fread(header, 1, 8, fd); int is_png = !png_sig_cmp(header, 0, 8); if (!is_png) { printf("ERROR: %s is not a valid png file\n", filepath.c_str()); fclose(fd); return; } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fclose(fd); return; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL); fclose(fd); return; } 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(fd); return; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fd); return; } png_init_io(png_ptr, fd); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); GLint bit_depth, color_type; png_get_IHDR(png_ptr, info_ptr, &m_width, &m_height, &bit_depth, &color_type, NULL, NULL, NULL); png_read_update_info(png_ptr, info_ptr); int rowbytes = png_get_rowbytes(png_ptr, info_ptr); png_byte *image_data = new png_byte[rowbytes * m_height]; if (!image_data) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fd); return; } png_bytep *row_pointers = new png_bytep[m_height]; if (!row_pointers) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); delete[] image_data; fclose(fd); return; } for (GLuint i = 0; i < m_height; ++i) { row_pointers[i] = image_data + i * rowbytes; } png_read_image(png_ptr, row_pointers); glGenTextures(1, &m_glTextureID); m_dataType = GL_UNSIGNED_BYTE; m_pixelFormat = GL_RGBA; m_targetType = GL_TEXTURE_2D; glBindTexture(m_targetType, m_glTextureID); glTexImage2D(m_targetType,0, m_pixelFormat, m_width, m_height, 0, m_pixelFormat, m_dataType, (GLvoid*) image_data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); delete[] image_data; delete[] row_pointers; fclose(fd); }
GLuint TextureManager::addFromPNG(const std::string& id, const std::string& texturePath) { FILE *fp = fopen(texturePath.c_str(), "rb"); if(!fp) return GL_INVALID_VALUE; png_byte header[8]; fread(header, 1, 8, fp); if(png_sig_cmp(header, 0, 8)) { fclose(fp); return GL_INVALID_VALUE; } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png_ptr) return GL_INVALID_VALUE; png_infop info_ptr = png_create_info_struct(png_ptr); png_infop end_info = png_create_info_struct(png_ptr); if(!info_ptr || !end_info || setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return GL_INVALID_VALUE; } png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); int bit_depth, color_type; png_uint_32 twidth, theight; png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type, NULL, NULL, NULL); int width = twidth; int height = theight; png_read_update_info(png_ptr, info_ptr); int rowbytes = png_get_rowbytes(png_ptr, info_ptr); png_byte *image_data = new png_byte[rowbytes * height]; png_bytepp row_pointers = new png_bytep[height]; if(!image_data || !row_pointers) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); delete[] image_data; fclose(fp); return GL_INVALID_VALUE; } for(int i = 0; i < height; ++i) row_pointers[height - 1 - i] = image_data + i * rowbytes; png_read_image(png_ptr, row_pointers); bool hasAlpha; /* switch (info_ptr->color_type) { case PNG_COLOR_TYPE_RGBA: hasAlpha = true; break; case PNG_COLOR_TYPE_RGB: hasAlpha = false; break; default: png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return GL_INVALID_VALUE; }*/ glGenTextures(1, &textures[id]); glBindTexture(GL_TEXTURE_2D, textures[id]); glTexImage2D(GL_TEXTURE_2D, 0, hasAlpha ? GL_RGBA : GL_RGB, width, height, 0, hasAlpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*) image_data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); delete[] image_data; delete[] row_pointers; fclose(fp); return true; }
short load_inp_png_file(ImageData& img, const std::string& fname_inp, ProgramOptions& opts) { FILE* pngfile = fopen(fname_inp.c_str(),"rb"); if (pngfile == NULL) { perror(fname_inp.c_str()); return ERR_CANT_OPEN; } png_byte header[8]; if (fread(header,8,1,pngfile) != 1) { perror(fname_inp.c_str()); fclose(pngfile); return ERR_FILE_READ; } if (png_sig_cmp(header,0,8)) { LogErr("%s: Not a PNG file",fname_inp.c_str()); fclose(pngfile); return ERR_BAD_FILE; } img.png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!img.png_ptr) { LogErr("%s: png_create_read_struct error",fname_inp.c_str()); fclose(pngfile); return ERR_BAD_FILE; } img.info_ptr=png_create_info_struct(img.png_ptr); if (!img.info_ptr) { png_destroy_read_struct(&img.png_ptr, (png_infopp)NULL, (png_infopp)NULL); LogErr("%s: png_create_info_struct error",fname_inp.c_str()); fclose(pngfile); return ERR_BAD_FILE; } img.end_info=png_create_info_struct(img.png_ptr); if (!img.end_info) { png_destroy_read_struct(&img.png_ptr, &img.info_ptr, (png_infopp)NULL); LogErr("%s: png_create_info_struct error",fname_inp.c_str()); fclose(pngfile); return ERR_BAD_FILE; } if (setjmp(png_jmpbuf(img.png_ptr))) { png_destroy_read_struct(&img.png_ptr, &img.info_ptr, &img.end_info); LogErr("%s: PNG error",fname_inp.c_str()); fclose(pngfile); exit(1); } png_init_io(img.png_ptr, pngfile); png_set_sig_bytes(img.png_ptr,8); int trafo=PNG_TRANSFORM_PACKING|PNG_TRANSFORM_STRIP_16|PNG_TRANSFORM_EXPAND; png_read_png(img.png_ptr, img.info_ptr, trafo , NULL); int bit_depth, interlace_type, compression_type, filter_method; png_get_IHDR(img.png_ptr, img.info_ptr, &img.width, &img.height, &bit_depth, &img.color_type, &interlace_type, &compression_type, &filter_method); if ((img.color_type & PNG_COLOR_MASK_COLOR)==0) { LogErr("%s: Grayscale image not supported",fname_inp.c_str()); fclose(pngfile); return ERR_BAD_FILE; } fclose(pngfile); if (img.color_type==PNG_COLOR_TYPE_PALETTE) { LogErr("Invalid format. This shouldn't happen. PNG_TRANSFORM_EXPAND transforms image to RGB."); return ERR_BAD_FILE; } if (img.color_type & PNG_COLOR_MASK_ALPHA) { img.col_bits = 32; } else { img.col_bits = 24; } return ERR_OK; }
void *png_read_file(const char *name, png_uint_32 *_w, png_uint_32 *_h, check_w_h_constraint_t constraint, rgba_surface_allocator_t allocator) { png_uint_32 i, w, h, stride; png_structp png_ptr = NULL; png_bytep *row_ptrs = NULL; png_infop info_ptr = NULL; void *pixels, *s = NULL; png_byte header[8]; int type, bpp; FILE *f; f = fopen_unsafe(name, "rb"); if(!f) goto exit_out; if(fread(header, 1, 8, f) < 8) goto exit_close; if(png_sig_cmp(header, 0, 8)) goto exit_close; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png_ptr) goto exit_close; info_ptr = png_create_info_struct(png_ptr); if(!info_ptr) goto exit_free_close; if(setjmp(png_ptr->jmpbuf)) goto exit_free_close; png_init_io(png_ptr, f); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &w, &h, &bpp, &type, NULL, NULL, NULL); if(!constraint(w, h)) { warn("Requested image '%s' failed dimension checks.\n", name); goto exit_free_close; } if(type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); else if(type == PNG_COLOR_TYPE_GRAY_ALPHA || !(type & PNG_COLOR_MASK_COLOR)) png_set_gray_to_rgb(png_ptr); else if(!(type & PNG_COLOR_MASK_COLOR) && bpp < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); if(bpp == 16) png_set_strip_16(png_ptr); else if(bpp < 8) png_set_packing(png_ptr); if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); else if(!(type & PNG_COLOR_MASK_ALPHA)) png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER); // FIXME: Are these necessary? png_read_update_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &w, &h, &bpp, &type, NULL, NULL, NULL); row_ptrs = cmalloc(sizeof(png_bytep) * h); if(!row_ptrs) goto exit_free_close; s = allocator(w, h, &stride, &pixels); if(!s) goto exit_free_close; for(i = 0; i < h; i++) row_ptrs[i] = (png_bytep)(unsigned char *)pixels + i * stride; png_read_image(png_ptr, row_ptrs); if(_w) *_w = w; if(_h) *_h = h; exit_free_close: png_destroy_read_struct(&png_ptr, &info_ptr, NULL); free(row_ptrs); exit_close: fclose(f); exit_out: return s; }
bool LoadPng(const char *name, int &iWidth, int &iHeight, bool &hasAlpha, GLubyte **outData) { FILE *fp = NULL; fp = fopen(name, "rb"); if (fp == NULL) { return false; } png_structp png_ptr; png_infop info_ptr; unsigned int sig_read = 0; int color_type, interlace_type; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fclose(fp); return false; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(fp); png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); return false; } if (setjmp(png_jmpbuf(png_ptr))) { 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, sig_read); png_read_png(png_ptr, info_ptr, /*PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING |*/ PNG_TRANSFORM_EXPAND, png_voidp_NULL); iWidth = info_ptr->width; iHeight = info_ptr->height; switch (info_ptr->color_type) { case PNG_COLOR_TYPE_RGBA: hasAlpha = true; break; case PNG_COLOR_TYPE_RGB: hasAlpha = false; break; default: printf("color type %d is not supported \n ", info_ptr->color_type); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return false; } unsigned int row_bytes = png_get_rowbytes(png_ptr, info_ptr); *outData = (unsigned char*)malloc(row_bytes * iHeight); png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr); for (int i = 0; i < iHeight; ++i) { memcpy(*outData + (row_bytes * (iHeight - 1- i)), row_pointers[i], row_bytes); } png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); fclose(fp); return true; }
SEXP read_png(SEXP sFn, SEXP sNative, SEXP sInfo) { SEXP res = R_NilValue, info_list = R_NilValue, info_tail = R_NilValue; const char *fn; char header[8]; int native = asInteger(sNative), info = (asInteger(sInfo) == 1); FILE *f; read_job_t rj; png_structp png_ptr; png_infop info_ptr; if (TYPEOF(sFn) == RAWSXP) { rj.data = (char*) RAW(sFn); rj.len = LENGTH(sFn); rj.ptr = 0; rj.f = f = 0; } else { if (TYPEOF(sFn) != STRSXP || LENGTH(sFn) < 1) Rf_error("invalid filename"); fn = CHAR(STRING_ELT(sFn, 0)); f = fopen(fn, "rb"); if (!f) Rf_error("unable to open %s", fn); if (fread(header, 1, 8, f) < 1 || png_sig_cmp((png_bytep) header, 0, 8)) { fclose(f); Rf_error("file is not in PNG format"); } rj.f = f; } /* use our own error hanlding code and pass the fp so it can be closed on error */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)&rj, user_error_fn, user_warning_fn); if (!png_ptr) { if (f) fclose(f); Rf_error("unable to initialize libpng"); } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { if (f) fclose(f); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); Rf_error("unable to initialize libpng"); } if (f) { png_init_io(png_ptr, f); png_set_sig_bytes(png_ptr, 8); } else png_set_read_fn(png_ptr, (png_voidp) &rj, user_read_data); #define add_info(K, V) { info_tail = SETCDR(info_tail, CONS(V, R_NilValue)); SET_TAG(info_tail, install(K)); } /* png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_EXPAND, NULL); */ png_read_info(png_ptr, info_ptr); { png_uint_32 width, height; png_bytepp row_pointers; char *img_memory; SEXP dim; int bit_depth, color_type, interlace_type, compression_type, filter_method, rowbytes; int need_swap = 0; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_method); rowbytes = png_get_rowbytes(png_ptr, info_ptr); #if VERBOSE_INFO Rprintf("png: %d x %d [%d], %d bytes, 0x%x, %d, %d\n", (int) width, (int) height, bit_depth, rowbytes, color_type, interlace_type, compression_type, filter_method); #endif if (info) { SEXP dv; double d; png_uint_32 rx, ry; int ut, num_text = 0; png_textp text_ptr; info_tail = info_list = PROTECT(CONS((dv = allocVector(INTSXP, 2)), R_NilValue)); INTEGER(dv)[0] = (int) width; INTEGER(dv)[1] = (int) height; SET_TAG(info_list, install("dim")); add_info("bit.depth", ScalarInteger(bit_depth)); switch(color_type) { case PNG_COLOR_TYPE_GRAY: add_info("color.type", mkString("gray")); break; case PNG_COLOR_TYPE_GRAY_ALPHA: add_info("color.type", mkString("gray + alpha")); break; case PNG_COLOR_TYPE_PALETTE: add_info("color.type", mkString("palette")); break; case PNG_COLOR_TYPE_RGB: add_info("color.type", mkString("RGB")); break; case PNG_COLOR_TYPE_RGB_ALPHA: add_info("color.type", mkString("RGBA")); break; default: add_info("color.type", ScalarInteger(color_type)); } if (png_get_gAMA(png_ptr, info_ptr, &d)) add_info("gamma", ScalarReal(d)); #ifdef PNG_pHYs_SUPPORTED if (png_get_pHYs(png_ptr, info_ptr, &rx, &ry, &ut)) { if (ut == PNG_RESOLUTION_METER) { dv = allocVector(REALSXP, 2); REAL(dv)[0] = ((double)rx) / 39.37008; REAL(dv)[1] = ((double)ry) / 39.37008; add_info("dpi", dv); } else if (ut == PNG_RESOLUTION_UNKNOWN) add_info("asp", ScalarReal(rx / ry)); } if (png_get_text(png_ptr, info_ptr, &text_ptr, &num_text)) { SEXP txt_key, txt_val = PROTECT(allocVector(STRSXP, num_text)); if (num_text) { int i; setAttrib(txt_val, R_NamesSymbol, txt_key = allocVector(STRSXP, num_text)); for (i = 0; i < num_text; i++) { SET_STRING_ELT(txt_val, i, text_ptr[i].text ? mkChar(text_ptr[i].text) : NA_STRING); SET_STRING_ELT(txt_key, i, text_ptr[i].key ? mkChar(text_ptr[i].key) : NA_STRING); } } add_info("text", txt_val); UNPROTECT(1); } #endif } /* on little-endian machines it's all well, but on big-endian ones we'll have to swap */ #if ! defined (__BIG_ENDIAN__) && ! defined (__LITTLE_ENDIAN__) /* old compiler so have to use run-time check */ { char bo[4] = { 1, 0, 0, 0 }; int bi; memcpy(&bi, bo, 4); if (bi != 1) need_swap = 1; } #endif #ifdef __BIG_ENDIAN__ need_swap = 1; #endif /*==== set any transforms that we desire: ====*/ /* palette->RGB - no discussion there */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); /* expand gray scale to 8 bits */ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); /* this should not be necessary but it's in the docs to guarantee 8-bit */ if (bit_depth < 8) png_set_packing(png_ptr); /* convert tRNS chunk into alpha */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); /* native format doesn't allow for 16-bit so it needs to be truncated */ if (bit_depth == 16 && native) { Rf_warning("Image uses 16-bit channels but R native format only supports 8-bit, truncating LSB."); png_set_strip_16(png_ptr); } /* for native output we need to a) convert gray to RGB, b) add alpha */ if (native) { 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_MASK_ALPHA)) /* if there is no alpha, add it */ png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER); } #if 0 /* we use native (network) endianness since we read each byte anyway */ /* on little-endian machines we need to swap 16-bit values - this is the inverse of need_swap as used for R! */ if (!need_swap && bit_depth == 16) png_set_swap(png_ptr); #endif /* PNG wants up to call png_set_interlace_handling so it can get ready to de-interlace images */ png_set_interlace_handling(png_ptr); /* all transformations are in place, so it's time to update the info structure so we can allocate stuff */ png_read_update_info(png_ptr, info_ptr); /* re-read some important bits from the updated structure */ rowbytes = png_get_rowbytes(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); #if VERBOSE_INFO Rprintf(" -filter-> %d-bits, %d bytes, 0x%x\n", bit_depth, rowbytes, color_type); #endif /* allocate data fro row pointers and the image using R's allocation */ row_pointers = (png_bytepp) R_alloc(height, sizeof(png_bytep)); img_memory = R_alloc(height, rowbytes); { /* populate the row pointers */ char *i_ptr = img_memory; int i; for (i = 0; i < height; i++, i_ptr += rowbytes) row_pointers[i] = (png_bytep) i_ptr; } /* do the reading work */ png_read_image(png_ptr, row_pointers); if (f) { rj.f = 0; fclose(f); } /* native output - vector of integers */ if (native) { int pln = rowbytes / width; if (pln < 1 || pln > 4) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); Rf_error("native output for %d planes is not possible.", pln); } res = PROTECT(allocVector(INTSXP, width * height)); if (pln == 4) { /* 4 planes - efficient - just copy it all */ int y, *idata = INTEGER(res); for (y = 0; y < height; idata += width, y++) memcpy(idata, row_pointers[y], width * sizeof(int)); if (need_swap) { int *ide = idata; idata = INTEGER(res); for (; idata < ide; idata++) RX_swap32(*idata); } } else if (pln == 3) { /* RGB */ int x, y, *idata = INTEGER(res); for (y = 0; y < height; y++) for (x = 0; x < rowbytes; x += 3) *(idata++) = R_RGB((unsigned int) row_pointers[y][x], (unsigned int) row_pointers[y][x + 1], (unsigned int) row_pointers[y][x + 2]); } else if (pln == 2) { /* GA */ int x, y, *idata = INTEGER(res); for (y = 0; y < height; y++) for (x = 0; x < rowbytes; x += 2) *(idata++) = R_RGBA((unsigned int) row_pointers[y][x], (unsigned int) row_pointers[y][x], (unsigned int) row_pointers[y][x], (unsigned int) row_pointers[y][x + 1]); } else { /* gray */ int x, y, *idata = INTEGER(res); for (y = 0; y < height; y++) for (x = 0; x < rowbytes; x++) *(idata++) = R_RGB((unsigned int) row_pointers[y][x], (unsigned int) row_pointers[y][x], (unsigned int) row_pointers[y][x]); } dim = allocVector(INTSXP, 2); INTEGER(dim)[0] = height; INTEGER(dim)[1] = width; setAttrib(res, R_DimSymbol, dim); setAttrib(res, R_ClassSymbol, mkString("nativeRaster")); setAttrib(res, install("channels"), ScalarInteger(pln)); UNPROTECT(1); } else { int x, y, p, pln = rowbytes / width, pls = width * height; double * data; if (bit_depth == 16) { res = PROTECT(allocVector(REALSXP, (rowbytes * height) / 2)); pln /= 2; } else res = PROTECT(allocVector(REALSXP, rowbytes * height)); data = REAL(res); if (bit_depth == 16) for(y = 0; y < height; y++) for (x = 0; x < width; x++) for (p = 0; p < pln; p++) data[y + x * height + p * pls] = ((double)( (((unsigned int)(((unsigned char *)row_pointers[y])[2 * (x * pln + p)])) << 8) | ((unsigned int)(((unsigned char *)row_pointers[y])[2 * (x * pln + p) + 1])) )) / 65535.0; else for(y = 0; y < height; y++) for (x = 0; x < width; x++) for (p = 0; p < pln; p++) data[y + x * height + p * pls] = ((double)row_pointers[y][x * pln + p]) / 255.0; dim = allocVector(INTSXP, (pln > 1) ? 3 : 2); INTEGER(dim)[0] = height; INTEGER(dim)[1] = width; if (pln > 1) INTEGER(dim)[2] = pln; setAttrib(res, R_DimSymbol, dim); UNPROTECT(1); } } if (info) { PROTECT(res); setAttrib(res, install("info"), info_list); UNPROTECT(2); } png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return res; }
uint8_t *PNG_unpack(SYS_FILEHANDLE infile, uint32_t *LX, uint32_t *LY, int *dwBitsPerPixel, rgb24_t *pClut, int options) { uint8_t *out_buffer; uint32_t i; unsigned char sig[8]; png_structp png_ptr; png_infop info_ptr; FIO_cur->fread(sig, 1, 8, infile); if (!png_check_sig(sig, 8)) { return NULL; /* bad signature */ } png_ptr = png_create_read_struct_2( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)pngx_error, (png_error_ptr)pngx_warning, (png_voidp)NULL, (png_malloc_ptr)pngx_malloc, (png_free_ptr)pngx_free); png_init_io(png_ptr, (FILE*)infile); png_set_sig_bytes(png_ptr, 8); /* we already read the 8 signature bytes */ png_set_read_fn(png_ptr, (FILE*)infile, pngx_readm_pData); if (!pClut) pClut = (rgb24_t*)MM_heap.malloc(3*256); info_ptr = png_create_info_struct(png_ptr); png_read_info(png_ptr, info_ptr); /* read all PNG info up to image data */ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } out_buffer = 0; if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) { png_colorp palette; int num_palette; png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); if (palette) sysMemCpy(pClut, palette, num_palette * 3); } else { for (i=0;i<256;i++) pClut[i].r = pClut[i].g = pClut[i].b = (uint8_t)i; } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) { double gamma; png_get_gAMA(png_ptr, info_ptr, &gamma); } if (options & 1) { png_uint_32 width, height; int bit_depth, rowbytes; int color_type; uint8_t **row_pointers = NULL; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); if (bit_depth<8) png_set_packing(png_ptr); if ((color_type == PNG_COLOR_TYPE_RGB_ALPHA && bit_depth>8)) png_set_bgr(png_ptr); png_read_update_info(png_ptr, info_ptr); rowbytes = png_get_rowbytes(png_ptr, info_ptr); out_buffer = (uint8_t*) MM_heap.malloc(height * rowbytes); row_pointers = (uint8_t**) MM_std.malloc(sizeof(char*)*height); SYS_ASSERT(row_pointers!=0); for (i=0;i<height;i++) row_pointers[i] = out_buffer + i * rowbytes; png_read_image(png_ptr, row_pointers); MM_std.free(row_pointers); png_read_end(png_ptr, NULL); *LX = width; *LY = height; *dwBitsPerPixel = (rowbytes<<3) / width; png_destroy_read_struct(&png_ptr, &info_ptr, NULL); } return out_buffer; }
// Read the PNG file using the libpng. The low-level interface is used here // because we want to do various transformations (including applying gama) // which can't be done with the high-level interface. // The scanline also begins at the bottom of // the image (per SecondLife conventions) instead of at the top, so we // must assign row-pointers in "reverse" order. BOOL LLPngWrapper::readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInfo *infop) { try { // Create and initialize the png structures mReadPngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, this, &errorHandler, NULL); if (mReadPngPtr == NULL) { throw "Problem creating png read structure"; } // Allocate/initialize the memory for image information. mReadInfoPtr = png_create_info_struct(mReadPngPtr); // Set up the input control PngDataInfo dataPtr; dataPtr.mData = src; dataPtr.mOffset = 0; dataPtr.mDataSize = dataSize; png_set_read_fn(mReadPngPtr, &dataPtr, &readDataCallback); png_set_sig_bytes(mReadPngPtr, 0); // setup low-level read and get header information png_read_info(mReadPngPtr, mReadInfoPtr); png_get_IHDR(mReadPngPtr, mReadInfoPtr, &mWidth, &mHeight, &mBitDepth, &mColorType, &mInterlaceType, &mCompressionType, &mFilterMethod); // Normalize the image, then get updated image information // after transformations have been applied normalizeImage(); updateMetaData(); // If a raw object is supplied, read the PNG image into its // data space if (rawImage != NULL) { rawImage->resize(static_cast<U16>(mWidth), static_cast<U16>(mHeight), mChannels); U8 *dest = rawImage->getData(); int offset = mWidth * mChannels; // Set up the row pointers and read the image mRowPointers = new U8* [mHeight]; for (U32 i=0; i < mHeight; i++) { mRowPointers[i] = &dest[(mHeight-i-1)*offset]; } png_read_image(mReadPngPtr, mRowPointers); // Finish up, ensures all metadata are updated png_read_end(mReadPngPtr, NULL); } // If an info object is supplied, copy the relevant info if (infop != NULL) { infop->mHeight = static_cast<U16>(mHeight); infop->mWidth = static_cast<U16>(mWidth); infop->mComponents = mChannels; } mFinalSize = dataPtr.mOffset; } catch (png_const_charp msg) { mErrorMessage = msg; releaseResources(); return (FALSE); } // Clean up and return releaseResources(); return (TRUE); }
bool texture_png_read(Texture* tex) { FILE *f; png_byte magic[8]; f = fopen(tex->filename, "rb"); if (!f) { fprintf (stderr, "error: couldn't open \"%s\"!\n", tex->filename); return false; } /* read magic number */ fread(magic, 1, sizeof(magic), f); /* check for valid magic number */ if (!png_check_sig(magic, sizeof(magic))) { fprintf(stderr, "error: \"%s\" is not a valid PNG image!\n", tex->filename); fclose(f); return false; } /* create a png read struct */ png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fclose(f); return false; } /* create a png info struct */ png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { fclose(f); png_destroy_read_struct(&png_ptr, NULL, NULL); return false; } /* initialize the setjmp for returning properly after a libpng error occured */ if (setjmp(png_jmpbuf(png_ptr))) { fclose(f); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); if (tex) { if (tex->data) free(tex->data); free(tex); } return false; } /* setup libpng for using standard C fread() function with our FILE pointer */ png_init_io(png_ptr, f); /* tell libpng that we have already read the magic number */ png_set_sig_bytes(png_ptr, sizeof(magic)); /* read png info */ png_read_info(png_ptr, info_ptr); /* get some usefull information from header */ int bit_depth = png_get_bit_depth(png_ptr, info_ptr); int color_type = png_get_color_type(png_ptr, info_ptr); /* convert index color images to RGB images */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); /* convert 1-2-4 bits grayscale images to 8 bits grayscale. */ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); else if (bit_depth < 8) png_set_packing(png_ptr); /* update info structure to apply transformations */ png_read_update_info(png_ptr, info_ptr); /* retrieve updated information */ png_get_IHDR(png_ptr, info_ptr, (png_uint_32*)(&tex->width), (png_uint_32*)(&tex->height), &bit_depth, &color_type, NULL, NULL, NULL); switch (color_type) { case PNG_COLOR_TYPE_GRAY: tex->format = GL_LUMINANCE; tex->internal_format = 1; break; case PNG_COLOR_TYPE_GRAY_ALPHA: tex->format = GL_LUMINANCE_ALPHA; tex->internal_format = 2; break; case PNG_COLOR_TYPE_RGB: tex->format = GL_RGB; tex->internal_format = 3; break; case PNG_COLOR_TYPE_RGB_ALPHA: tex->format = GL_RGBA; tex->internal_format = 4; break; default: printf("color type not found\n"); break; } /* we can now allocate memory for storing pixel data */ tex->data = (GLubyte*) malloc(sizeof(GLubyte) * tex->width * tex->height * tex->internal_format); png_bytep* row_pointers; /* setup a pointer array. Each one points at the begening of a row. */ row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * tex->height); int i; for (i = 0; i < tex->height; ++i) { row_pointers[i] = (png_bytep)(tex->data + ((tex->height - (i + 1)) * tex->width * tex->internal_format)); } /* read pixel data using row pointers */ png_read_image(png_ptr, row_pointers); /* we don't need row pointers anymore */ free(row_pointers); /* finish decompression and release memory */ png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(f); tex->state = 1; return true; }
/* ReadPNG - Reads the contents of a PNG file and stores the contents into BMGImageStruct Inputs: filename - the name of the file to be opened Outputs: img - the BMGImageStruct containing the image data Returns: BMGError - if the file could not be read or a resource error occurred BMG_OK - if the file was read and the data was stored in img Limitations: None. Comments: 2-bit images are converted to 4-bit images. 16-bit images are converted to 8-bit images. gray scale images with alpha components are converted to 32-bit images */ BMGError ReadPNG( const char *filename, struct BMGImageStruct * volatile img ) { jmp_buf err_jmp; int error; FILE * volatile file = NULL; int BitDepth; int ColorType; int InterlaceType; unsigned char signature[8]; png_structp volatile png_ptr = NULL; png_infop volatile info_ptr = NULL; png_infop volatile end_info = NULL; png_color_16 *ImageBackground = NULL; png_bytep trns = NULL; int NumTrans = 0; int i, k; png_color_16p TransColors = NULL; png_uint_32 Width, Height; unsigned char *bits; unsigned char** volatile rows = NULL; BMGError tmp; /* error handler */ error = setjmp( err_jmp ); if (error != 0) { if (end_info != NULL) png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info); else if (info_ptr != NULL) png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, NULL); else if (png_ptr != NULL) png_destroy_read_struct((png_structp *) &png_ptr, NULL, NULL); if (rows) { if (rows[0]) free(rows[0]); free(rows); } if (img) FreeBMGImage(img); if (file) fclose(file); SetLastBMGError((BMGError) error); return (BMGError) error; } if ( img == NULL ) longjmp ( err_jmp, (int)errInvalidBMGImage ); file = fopen( filename, "rb" ); if ( !file || fread( signature, 1, 8, file ) != 8) longjmp ( err_jmp, (int)errFileOpen ); /* check the signature */ if ( png_sig_cmp( signature, 0, 8 ) != 0 ) longjmp( err_jmp, (int)errUnsupportedFileFormat ); /* create a pointer to the png read structure */ png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); if ( !png_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create a pointer to the png info structure */ info_ptr = png_create_info_struct( png_ptr ); if ( !info_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create a pointer to the png end-info structure */ end_info = png_create_info_struct(png_ptr); if (!end_info) longjmp( err_jmp, (int)errMemoryAllocation ); /* bamboozle the PNG longjmp buffer */ /*generic PNG error handler*/ /* error will always == 1 which == errLib */ // error = png_setjmp(png_ptr); error = setjmp( png_jmpbuf( png_ptr ) ); if ( error > 0 ) longjmp( err_jmp, error ); /* set function pointers in the PNG library, for read callbacks */ png_set_read_fn(png_ptr, (png_voidp) file, user_read_data); /*let the read functions know that we have already read the 1st 8 bytes */ png_set_sig_bytes( png_ptr, 8 ); /* read all PNG data up to the image data */ png_read_info( png_ptr, info_ptr ); /* extract the data we need to form the HBITMAP from the PNG header */ png_get_IHDR( png_ptr, info_ptr, &Width, &Height, &BitDepth, &ColorType, &InterlaceType, NULL, NULL); img->width = (unsigned int) Width; img->height = (unsigned int) Height; img->bits_per_pixel = (unsigned char)32; img->scan_width = Width * 4; /* convert 16-bit images to 8-bit images */ if (BitDepth == 16) png_set_strip_16(png_ptr); /* These are not really required per Rice format spec, * but is done just in case someone uses them. */ /* convert palette color to rgb color */ if (ColorType == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); ColorType = PNG_COLOR_TYPE_RGB; } /* expand 1,2,4 bit gray scale to 8 bit gray scale */ if (ColorType == PNG_COLOR_TYPE_GRAY && BitDepth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); /* convert gray scale or gray scale + alpha to rgb color */ if (ColorType == PNG_COLOR_TYPE_GRAY || ColorType == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); ColorType = PNG_COLOR_TYPE_RGB; } /* add alpha channel if any */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); ColorType = PNG_COLOR_TYPE_RGB_ALPHA; } /* convert rgb to rgba */ if (ColorType == PNG_COLOR_TYPE_RGB) { png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); ColorType = PNG_COLOR_TYPE_RGB_ALPHA; } png_set_bgr(png_ptr); /* set the background color if one is found */ if ( png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD) ) png_get_bKGD(png_ptr, info_ptr, &ImageBackground); /* get the transparent color if one is there */ if ( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) ) png_get_tRNS( png_ptr, info_ptr, &trns, &NumTrans, &TransColors ); img->palette_size = (unsigned short)0; img->bytes_per_palette_entry = 4U; tmp = AllocateBMGImage( img ); if ( tmp != BMG_OK ) longjmp( err_jmp, (int)tmp ); png_read_update_info( png_ptr, info_ptr ); /* create buffer to read data to */ rows = (unsigned char **)malloc(Height*sizeof(unsigned char *)); if ( !rows ) longjmp( err_jmp, (int)errMemoryAllocation ); k = png_get_rowbytes( png_ptr, info_ptr ); rows[0] = (unsigned char *)malloc( Height*k*sizeof(char)); if ( !rows[0] ) longjmp( err_jmp, (int)errMemoryAllocation ); for ( i = 1; i < (int)Height; i++ ) rows[i] = rows[i-1] + k; /* read the entire image into rows */ png_read_image( png_ptr, rows ); bits = img->bits + (Height - 1) * img->scan_width; for ( i = 0; i < (int)Height; i++ ) { memcpy(bits, rows[i], 4*Width); bits -= img->scan_width; } free( rows[0] ); free( rows ); png_read_end( png_ptr, info_ptr ); png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info); fclose( file ); return BMG_OK; }
Py::Object _image_module::readpng(const Py::Tuple& args) { args.verify_length(1); std::string fname = Py::String(args[0]); png_byte header[8]; // 8 is the maximum size that can be checked FILE *fp = fopen(fname.c_str(), "rb"); if (!fp) throw Py::RuntimeError(Printf("_image_module::readpng could not open PNG file %s for reading", fname.c_str()).str()); fread(header, 1, 8, fp); 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"); png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); png_uint_32 width = info_ptr->width; png_uint_32 height = info_ptr->height; // convert misc color types to rgb for simplicity if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY || info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); int bit_depth = info_ptr->bit_depth; if (bit_depth == 16) png_set_strip_16(png_ptr); png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); bool rgba = info_ptr->color_type == PNG_COLOR_TYPE_RGBA; if ( (info_ptr->color_type != PNG_COLOR_TYPE_RGB) && !rgba) { std::cerr << "Found color type " << (int)info_ptr->color_type << std::endl; throw Py::RuntimeError("_image_module::readpng: cannot handle color_type"); } /* read file */ if (setjmp(png_jmpbuf(png_ptr))) throw Py::RuntimeError("_image_module::readpng: error during read_image"); png_bytep row_pointers[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); int dimensions[3]; dimensions[0] = height; //numrows dimensions[1] = width; //numcols dimensions[2] = 4; PyArrayObject *A = (PyArrayObject *) PyArray_FromDims(3, dimensions, PyArray_FLOAT); 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 = (rgba) ? &(row[x*4]) : &(row[x*3]); size_t offset = y*A->strides[0] + x*A->strides[1]; //if ((y<10)&&(x==10)) std::cout << "r = " << ptr[0] << " " << ptr[0]/255.0 << std::endl; *(float*)(A->data + offset + 0*A->strides[2]) = ptr[0]/255.0; *(float*)(A->data + offset + 1*A->strides[2]) = ptr[1]/255.0; *(float*)(A->data + offset + 2*A->strides[2]) = ptr[2]/255.0; *(float*)(A->data + offset + 3*A->strides[2]) = rgba ? ptr[3]/255.0 : 1.0; } } //free the png memory png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); fclose(fp); for (png_uint_32 row = 0; row < height; row++) delete [] row_pointers[row]; return Py::asObject((PyObject*)A); }
// This is the interesting function here. It sets up a PNG image as a texture. void loadPngTex(char * fname , struct tImagePNG * pImagePNG , int *hasAlpha ) { // The header of the file will be saved in here char buf[PNG_BYTES_TO_CHECK]; // images infos int bit_depth; int cType; double gamma; FILE *fp; // Open the file and check correct opening /* Open the prospective PNG file. */ if ((fp = fopen(fname, "rb")) == NULL) { printf( "Error: Could not open the texture file [%s]!" , fname ); throw 336; } // Read the PNG header, which is 8 bytes long. /* Read in some of the signature bytes */ if (fread(buf, 1, PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK) { printf( "Error: Incorrect PNG texture file [%s]!" , fname ); throw 336; } // Check whether the file is a PNG file // png_sig_cmp() checks the given PNG header and returns 0 if it could // be the start of a PNG file. We can use 8 bytes at max for // this comparison. if(png_sig_cmp((png_byte*)buf, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) { fclose( fp ); printf( "Error: Not a PNG file [%s]!" , fname ); throw 337; } // Create / initialize the png_struct // The png_struct isn't directly accessed by the user (us). // We will later create a png_info from this to get access to the // PNG's infos. // The three 0's in the arg list could be pointers to user defined error // handling functions. 0 means we don't want to specify them, but use // libPNG's default error handling instead. png_infop info_ptr; png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL , NULL , NULL ); if(!png_ptr) { fclose( fp ); printf( "Error: Couldn't create PNG read structure [%s]!" , fname ); throw 338; } // Create / initialize the png_info // The png_info grants the user access to the PNG infos. info_ptr = png_create_info_struct(png_ptr); if(!info_ptr) { // We need to destroy the read_struct png_destroy_read_struct(&png_ptr, NULL, NULL); fclose( fp ); printf( "Error: Couldn't create PNG info structure [%s]!" , fname ); throw 339; } // Setup error handler // This sets the point libPNG jumps back to is an error occurs. if (setjmp(png_jmpbuf(png_ptr))) { /* Free all of the memory associated with the png_ptr and info_ptr */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); fclose(fp); /* If we get here, we had a problem reading the file */ printf( "Error: Couldn't setup PNG error handler [%s]!" , fname ); throw 340; } /* Set up the input control if you are using standard C streams */ png_init_io(png_ptr, fp); // This tells libPNG that we have already read 8 bytes from the start // of the file (for the header check above). png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); // This reads the PNG file into the read and info structs /* * If you have enough memory to read in the entire image at once, * and you need to specify only transforms that can be controlled * with one of the PNG_TRANSFORM_* bits (this presently excludes * dithering, filling, setting background, and doing gamma * adjustment), then you can read the entire image (including * pixels) into the info structure with this call: */ png_read_info(png_ptr, info_ptr); // Get some basic infos about the image from png_info structure // width & height in px, bit depth // interlace_method, compression_method, & filter_method are ignored png_get_IHDR(png_ptr, info_ptr, &(pImagePNG->sizeX), &(pImagePNG->sizeY), &bit_depth, &cType, 0, 0, 0); // COLOR TYPE read and possible corrections - then reread // Color type: we handle RGB and RGB_ALPHA (with Alpha) // GRAY (luminance) and GRAY_ALPHA (luminance with Alpha) cType = png_get_color_type(png_ptr, info_ptr); // strip the pixels of a PNG stream with 16 bits per channel to 8 bits per channel if (bit_depth == 16) { png_set_strip_16(png_ptr); } // set transformation in png_ptr such that paletted images are expanded to RGB, // grayscale images of bit-depth less than 8 are expanded to 8-bit images // tRNS chunks are expanded to alpha channels if (cType == PNG_COLOR_TYPE_PALETTE) { png_set_expand(png_ptr); } if (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 required set gamma conversion if (png_get_gAMA(png_ptr, info_ptr, &gamma)) { png_set_gamma(png_ptr, (double) 2.2, gamma); } // After the image transformations have been registered update info_ptr data png_read_update_info(png_ptr, info_ptr); // Gets again width, height and the new bit-depth and color-type png_get_IHDR(png_ptr, info_ptr, &(pImagePNG->sizeX), &(pImagePNG->sizeY), &bit_depth, &cType, 0, 0, 0); // We now calculate the *bytes* per pixel from the color type and the // bits per pixel. if((cType == PNG_COLOR_TYPE_RGB) && (bit_depth == 8)) { pImagePNG->bytesPerPixel = 3; *hasAlpha = false; } else if((cType == PNG_COLOR_TYPE_RGB_ALPHA) && (bit_depth == 8)) { pImagePNG->bytesPerPixel = 4; *hasAlpha = true; } else if((cType == PNG_COLOR_TYPE_GRAY) && (bit_depth == 8)) { pImagePNG->bytesPerPixel = 1; *hasAlpha = false; } else if((cType == PNG_COLOR_TYPE_GRAY_ALPHA) && (bit_depth == 8)) { pImagePNG->bytesPerPixel = 2; *hasAlpha = true; } else { /* clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); fclose( fp ); printf( "Error: PNG image [%s] type (%d) bit depth (%d) is unsupported!" , fname , cType , bit_depth ); throw 336; } // rowbytes is the width x number of channels. channels is not used currently unsigned int rowbytes = png_get_rowbytes(png_ptr, info_ptr); // unsigned int channels = png_get_channels(png_ptr, info_ptr); // Allocates memory to store the image pImagePNG->data = new GLubyte[pImagePNG->sizeY * rowbytes]; // printf( "PNG image %ldx%ld (%d bitsperpixel/%d bytesPerPixel) size row %d total %ld\n" , // pImagePNG->sizeX , // pImagePNG->sizeY , bit_depth , pImagePNG->bytesPerPixel, // rowbytes , pImagePNG->sizeY * rowbytes); //// Alternate solution without explicit row pointers //// and image read through png_get_rows // Returns a pointer to the array of array of png_bytes that holds the // image data. // png_byte **imageData = png_get_rows(png_ptr, info_ptr); //// must read row after row // for( unsigned int i = 0 ; i < pImagePNG->sizeY ; i++ ) { // printf( "Ind %d\n" , i ); // memcpy(&pImagePNG->data[(pImagePNG->sizeY - i - 1) * rowbytes], // row[i], rowbytes); // } //// Alternate solution with explicit row pointers //// and image read through png_read_image // Allocates memory for an array of row-pointers png_byte ** row = new GLubyte * [pImagePNG->sizeY]; // Sets the row-pointers to point at the correct offsets for (unsigned int i = 0; i < pImagePNG->sizeY; i++) { row[i] = pImagePNG->data + (pImagePNG->sizeY - i - 1) * rowbytes; } // Reads the whole image png_read_image(png_ptr, row); // deallocate the now unuseful row pointers delete [] row; // Free the memory we used - we don't need it anymore /* clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); fclose( fp ); }
PyObject* _png_module::_read_png(const Py::Object& py_fileobj, const bool float_result, int result_bit_depth) { png_byte header[8]; // 8 is the maximum size that can be checked FILE* fp = NULL; bool close_file = false; bool close_dup_file = false; PyObject *py_file = NULL; if (py_fileobj.isString()) { if ((py_file = npy_PyFile_OpenFile(py_fileobj.ptr(), (char *)"rb")) == NULL) { throw Py::Exception(); } close_file = true; } else { py_file = py_fileobj.ptr(); } if ((fp = npy_PyFile_Dup(py_file, "rb"))) { 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); 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_file, 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_file, &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); 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); /* 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) - 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 { if (result_bit_depth < 0) { result_bit_depth = bit_depth; } if (result_bit_depth == 8) { A = (PyArrayObject *) PyArray_SimpleNew(num_dims, dimensions, NPY_UBYTE); } else if (result_bit_depth == 16) { A = (PyArrayObject *) PyArray_SimpleNew(num_dims, dimensions, NPY_UINT16); } else { throw Py::RuntimeError( "_image_module::readpng: image has unknown bit depth"); } 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]]; if (result_bit_depth == 16) { for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) { *(png_uint_16*)(A->data + offset + p*A->strides[2]) = ptr[p]; } } else { 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]]); if (result_bit_depth == 16) { for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) { *(png_uint_16*)(A->data + offset + p*A->strides[2]) = ptr[p]; } } else { 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 read_header(const char *filename, dt_imageio_png_t *png) { png->f = fopen(filename, "rb"); if(!png->f) return 1; const size_t NUM_BYTES_CHECK = 8; png_byte dat[NUM_BYTES_CHECK]; size_t cnt = fread(dat, 1, NUM_BYTES_CHECK, png->f); if(cnt != NUM_BYTES_CHECK || png_sig_cmp(dat, (png_size_t)0, NUM_BYTES_CHECK)) { fclose(png->f); return 1; } png->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png->png_ptr) { fclose(png->f); return 1; } png->info_ptr = png_create_info_struct(png->png_ptr); if(!png->info_ptr) { fclose(png->f); png_destroy_read_struct(&png->png_ptr, NULL, NULL); return 1; } if(setjmp(png_jmpbuf(png->png_ptr))) { fclose(png->f); png_destroy_read_struct(&png->png_ptr, &png->info_ptr, NULL); return 1; } png_init_io(png->png_ptr, png->f); // we checked some bytes png_set_sig_bytes(png->png_ptr, NUM_BYTES_CHECK); // image info png_read_info(png->png_ptr, png->info_ptr); png->bit_depth = png_get_bit_depth(png->png_ptr, png->info_ptr); png->color_type = png_get_color_type(png->png_ptr, png->info_ptr); // image input transformations // palette => rgb if(png->color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png->png_ptr); // 1, 2, 4 bit => 8 bit if(png->color_type == PNG_COLOR_TYPE_GRAY && png->bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png->png_ptr); png->bit_depth = 8; } // strip alpha channel if(png->color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png->png_ptr); // grayscale => rgb if(png->color_type == PNG_COLOR_TYPE_GRAY || png->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png->png_ptr); // reflect changes png_read_update_info(png->png_ptr, png->info_ptr); // png->bytespp = 3*bit_depth/8; png->width = png_get_image_width(png->png_ptr, png->info_ptr); png->height = png_get_image_height(png->png_ptr, png->info_ptr); return 0; }
void LinuxAppPlatform::loadPNG(ImageData& imgData, const std::string& path, bool b) { std::cout << "loadPNG: " << path << " (from assets: " << b << ")\n"; FILE* file = fopen(getImagePath(path, b).c_str(), "rb"); if (file == NULL) { std::cout << "failed to open file\n"; return; } png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png) { std::cout << "png_create_read_struct failed\n"; abort(); return; } png_infop info = png_create_info_struct(png); if (!info) { std::cout << "png_create_info_struct failed\n"; abort(); return; } unsigned char header[8]; if(fread(header, 8, 1, file) != 1) { std::cout << "failed to read png header\n"; return; } if(png_sig_cmp(header, 0, 8)) { std::cout << "header is invalid\n"; return; } if (setjmp(png_jmpbuf(png))) { std::cout << "failed to load png\n"; abort(); return; } png_init_io(png, file); png_set_sig_bytes(png, 8); png_read_info(png, info); imgData.w = (int) png_get_image_width(png, info); imgData.h = (int) png_get_image_height(png, info); imgData.format = TextureFormat::U8888; imgData.mipLevel = 0; png_byte bitDepth = png_get_bit_depth(png, info); png_byte colorType = png_get_color_type(png, info); switch(colorType){ case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(png); break; case PNG_COLOR_TYPE_RGB: if(png_get_valid(png, info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png); } else { png_set_filler(png, 0xff, PNG_FILLER_AFTER); } break; case PNG_COLOR_TYPE_RGB_ALPHA: break; case PNG_COLOR_TYPE_GRAY: if(bitDepth < 8) { png_set_expand_gray_1_2_4_to_8(png); } default: std::cout << "png: unsupported color type\n"; } if(bitDepth == 16) { png_set_strip_16(png); } png_read_update_info(png, info); png_size_t rowBytes = png_get_rowbytes(png, info); std::vector<char> data(rowBytes * imgData.h); png_byte* rows[imgData.h]; for (int i = 0; i < imgData.h; i++) { rows[i] = (png_byte*) &data[i * rowBytes]; } png_read_image(png, rows); fclose(file); { std::string empty; ((void **) &imgData.data)[0] = ((void **) &empty)[0]; imgData.data = " "; } imgData.data = std::string(&data[0], rowBytes * imgData.h); }
int read_png_(char *file_name, int *w, int *h, int *rw, int *rh, unsigned char *pixout[], bool forgl, int *numchannel) { png_structp png_ptr; png_infop info_ptr; unsigned int sig_read = 0; png_uint_32 width, height; int bit_depth, color_type, interlace_type, compression_type, filter_type; FILE *fp; if ((fp = fopen(file_name, "rb")) == NULL) return (ERROR); /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also supply the * the compiler header file version, so that we know if the application * was compiled with a compatible version of the library. REQUIRED */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fclose(fp); return (ERROR); } /* Allocate/initialize the memory for image information. REQUIRED. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(fp); png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); return (ERROR); } /* Set error handling if you are using the setjmp/longjmp method (this is * the normal method of doing things with libpng). REQUIRED unless you * set up your own error handlers in the png_create_read_struct() earlier. */ if (setjmp(png_jmpbuf(png_ptr))) { /* Free all of the memory associated with the png_ptr and info_ptr */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); fclose(fp); /* If we get here, we had a problem reading the file */ return (ERROR); } /* One of the following I/O initialization methods is REQUIRED */ /* Set up the input control if you are using standard C streams */ png_init_io(png_ptr, fp); /* If we have already read some of the signature */ png_set_sig_bytes(png_ptr, sig_read); png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type); // The following code transforms grayscale images of less than 8 to 8 bits, // changes paletted images to RGB, and adds a full alpha channel if there // is transparency information in a tRNS chunk. if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8) 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) //ensure 8-bit png_set_strip_16(png_ptr); if (bit_depth < 8) //ensure 8-bit png_set_packing(png_ptr); if (forgl) { //width and height must be powers of 2. *rh = height; //set the real return vals first *rw = width; //these are probably the only likely ranges if (width > 512) width = 1024; else if (width > 256) width = 512; else width = 256; if (height > 512) height = 1024; else if (height > 256) height = 512; else height = 256; } //printf("colortype %d %d\n",color_type,PNG_COLOR_TYPE_RGBA); *numchannel=3; if(color_type==PNG_COLOR_TYPE_RGBA||color_type==PNG_COLOR_TYPE_RGB_ALPHA) *numchannel=4; unsigned char *pixels = new unsigned char[width*height*sizeof(unsigned char)*(*numchannel)]; //for rgba png_byte **row_pointers = new png_byte*[height]; for (unsigned int k = 0; k < height; k++) row_pointers[k] = pixels + (k)* width*sizeof(unsigned char)*(*numchannel); //for r,g,b,a png_read_image(png_ptr, row_pointers); png_read_end(png_ptr, NULL); /* At this point you have read the entire image */ //set return values *h = height; *w = width; *pixout = pixels; /* clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); /* close the file */ fclose(fp); /* that's it */ return (OK); }
static unsigned char* _load_image_RGBA_png(const char *fileName, int *width, int *height) { // open the file FILE *fp = fopen(fileName, "rb"); if (!fp) return _load_img_error(width, height); // read the header const size_t HEADER_LENGTH = 8; png_byte header[HEADER_LENGTH]; size_t n = fread(header, 1, HEADER_LENGTH, fp); if (n != HEADER_LENGTH || png_sig_cmp(header, 0, HEADER_LENGTH)) return _load_img_error(width, height); // try to create the loading structures png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!png_ptr) { fclose(fp); return _load_img_error(width, height); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp) 0, (png_infopp) 0); fclose(fp); return _load_img_error(width, height); } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)0); fclose(fp); return _load_img_error(width, height); } if (setjmp(png_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return _load_img_error(width, height); } // start the io png_init_io(png_ptr, fp); // indicate that we have already read some of the hearder png_set_sig_bytes(png_ptr, HEADER_LENGTH); // read the image info, get some info 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); int bit_depth = png_get_bit_depth(png_ptr, info_ptr); png_byte color_type = png_get_color_type(png_ptr, info_ptr); // force the image into RGBA, 8 bits per channel if (color_type != PNG_COLOR_TYPE_RGBA) png_set_expand(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); else if (bit_depth == 16) png_set_strip_16(png_ptr); if (color_type != PNG_COLOR_TYPE_RGBA) png_set_filler(png_ptr, 255, PNG_FILLER_AFTER); png_read_update_info(png_ptr, info_ptr); // make sure we're actually in rgba mode if ((int)png_get_rowbytes(png_ptr, info_ptr) != ((*width) * 4)) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return _load_img_error(width, height); } // finally, read the file unsigned char *buffer = (unsigned char *) malloc((*width) * (*height) * 4); png_bytep *row_pointers = new png_bytep[*height]; for (int y = 0 ; y < (*height) ; y++) { row_pointers[y] = (png_byte *) (buffer + ((*height) - 1 - y) * (*width) * 4); } png_read_rows(png_ptr, row_pointers, 0, (long unsigned int) (*height)); // deallocate memory and return fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return buffer; }
int main(int argc, char **argv) { FILE *fin = NULL; FILE *fout = NULL; char header[8]; uint8_t *image_data = NULL; png_bytep *row_pointers = NULL; int i; if (argc < 3) ERR("too few arguments") if ((fin = fopen(argv[1], "rb")) == NULL) ERR("cannot open man, lame!"); printf("%s opened\n", argv[1]); fread(header, 1, 8, fin); if (png_check_sig(header, 8) == 0) ERR("not a valid .png image") png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) ERR("sdf"); png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); ERR2("fssdfs"); } if (setjmp(png_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return 0; } png_init_io(png_ptr, fin); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); printf("width : %d\n", info_ptr->width); printf("height : %d\n", info_ptr->height); printf("bpp : %d\n", info_ptr->bit_depth); printf("palette : %d entries\n", info_ptr->num_palette); printf("rowbytes : %d\n", info_ptr->rowbytes); /* fclose(fin); return 0; png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); ERR2("fjsh"); } */ // optional call to update palette with transformations // png_start_read_image(png_ptr); // optional call to update the info structure // png_read_update_info(png_ptr, info_ptr); if ((image_data = (uint8_t*)malloc(info_ptr->rowbytes*info_ptr->height)) == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return 0; } row_pointers = (png_bytep*)malloc(sizeof(png_bytep)*info_ptr->height); for (i=0; i<info_ptr->height; ++i) row_pointers[i] = image_data + i*info_ptr->rowbytes; // the easiest way to read the image png_read_image(png_ptr, row_pointers); // void write_binimg(char *fname, uint8_t *data, png_color *pal_data, int pal_size, int width, int height, int bpp) char filename[256]; strcpy(filename, argv[2]); /* write_binimg(strcat(filename, ".raw"), image_data, info_ptr->palette, info_ptr->num_palette, info_ptr->width, info_ptr->height, info_ptr->bit_depth); */ write_2c(argv[2], image_data, info_ptr->palette, info_ptr->num_palette, info_ptr->width, info_ptr->height, info_ptr->bit_depth); // clean up after the read, and free any memory allocated png_read_destroy(png_ptr, info_ptr, (png_infop)0); // png_read_end(png_ptr, NULL); i_am_done: if (image_data != NULL) free(image_data); if (row_pointers != NULL) free(row_pointers); if (fin != NULL) fclose(fin); if (fout != NULL) fclose(fout); return 0; }
CSize InformApp::GetImageSize(const char* path) { CSize size(0,0); // Check if it's a PNG file CStdioFile imageFile; if (!imageFile.Open(path,CFile::modeRead|CFile::typeBinary)) return size; png_byte fileHeader[8]; imageFile.Read(fileHeader,8); bool isPNG = (png_sig_cmp(fileHeader,0,8) == 0); if (isPNG) { png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,(png_voidp)NULL,NULL,NULL); if (png_ptr == NULL) return size; png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr,(png_infopp)NULL,(png_infopp)NULL); return size; } png_infop end_info = png_create_info_struct(png_ptr); if (end_info == NULL) { png_destroy_read_struct(&png_ptr,&info_ptr,(png_infopp)NULL); return size; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr,&info_ptr,&end_info); return size; } png_init_io(png_ptr,imageFile.m_pStream); png_set_sig_bytes(png_ptr,8); png_read_info(png_ptr,info_ptr); size.cx = png_get_image_width(png_ptr,info_ptr); size.cy = png_get_image_height(png_ptr,info_ptr); png_destroy_read_struct(&png_ptr,&info_ptr,&end_info); return size; } else { imageFile.SeekToBegin(); struct jpeg_decompress_struct info; struct JPEGErrorInfo error; info.err = jpeg_std_error(&(error.base)); error.base.error_exit = errorJPEGExit; error.base.output_message = outputJPEGMessage; if (setjmp(error.errorJump)) { jpeg_destroy_decompress(&info); return size; } jpeg_create_decompress(&info); jpeg_stdio_src(&info,imageFile.m_pStream); jpeg_read_header(&info,TRUE); jpeg_calc_output_dimensions(&info); size.cx = info.output_width; size.cy = info.output_height; jpeg_destroy_decompress(&info); return size; } }