I am using pHash and that library uses libpng. I am having issues running my program because libpng fails loading a PNG file.
Just if you came up with the following questions...
Library pHash uses CImg, the version of CImg they are using is a bit old I think:
#define cimg_version 148 // In CImg.h
I have debugged the library and the problems occurs in CImg.h
(contained in the pHash VC++ project):
CImg<T>& _load_png(std::FILE *const file, const char *const filename) {
if (!file && !filename)
throw CImgArgumentException(_cimg_instance
"load_png() : Specified filename is (null).",
cimg_instance);
// Open file and check for PNG validity
if (Buffer) strcat(Buffer, "Checking PNG availability\r\n");
const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'.
std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"rb");
unsigned char pngCheck[8] = { 0 };
cimg::fread(pngCheck,8,(std::FILE*)nfile);
if (png_sig_cmp(pngCheck,0,8)) {
if (!file) cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_png() : Invalid PNG file '%s'.",
cimg_instance,
nfilename?nfilename:"(FILE*)");
}
// Setup PNG structures for read
png_voidp user_error_ptr = 0;
png_error_ptr user_error_fn = 0, user_warning_fn = 0;
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,user_error_ptr,user_error_fn,user_warning_fn);
if (!png_ptr) { // <-- PROBLEM HERE
if (!file) cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_png() : Failed to initialize 'png_ptr' structure for file '%s'.",
cimg_instance,
nfilename?nfilename:"(FILE*)");
...
}
The snippet shows the first part of CImg<T>& _load_png(std::FILE *const file, const char *const filename)
which is called by the CImg library used by pHash.
The code compiles fine but I get this error at runtime which I can see in the debugger:
CImgIOException: Failed to initialize 'png_ptr'...
In the point indicated in the code. I don't know why, it fails loading the image. The failure occurs when calling png_create_read_struct
in CImg.h
. That code is a bit obscure as defined through preprocessor directives. It is not clear why it is failing.
Any ideas?
Either if you are including libpng yourself or if another library is including and using libpng there are a few things to be aware of.
It is a little to difficult to tell what exactly is causing the problem but these are a few things to have a look at.
One thing I would suggest is to go to the website that provides the newest version of libpng and download it. Set a folder on your computer and create "system environment variable through windows" to point to your library. Open the solution to this library in the current version of VS you are using, build it out for both a static lib and dynamic lib (two different solutions) and build them both out for 32 bit and 64 bit saving the generated files into separated folders. Then go into the other library that depends on this and try to switch the dlls or libs and link against the new ones if possible. Also the other 3rd party library you should try to open its solution in the same version of VS and try to do a clean build from there. Then make sure you link everything properly. You may have to also modify the props file.
EDIT
I am not familiar with pHash or CImg, but I am familiar with libpng.
Here is a function in one of my projects to load in a png into a texture structure. Now this is a part of a class object that relies on many other classes, but you should be able to see from this snippet that I am successfully using libpng.
// ----------------------------------------------------------------------------
// loadPng()
bool TextureFileReader::loadPng( Texture* pTexture ) {
struct PngFile {
FILE* fp;
png_struct* pStruct;
png_info* pInfo;
// --------------------------------------------------------------------
PngFile() :
fp( NULL ),
pStruct( NULL ),
pInfo( NULL )
{} // PngFile
// --------------------------------------------------------------------
~PngFile() {
if ( NULL != fp ) {
fclose( fp );
}
if ( NULL != pStruct ) {
if ( NULL != pInfo ) {
png_destroy_read_struct( &pStruct, &pInfo, NULL );
} else {
png_destroy_read_struct( &pStruct, NULL, NULL );
}
}
} // ~PngFile
} png;
// Error Message Handling
std::ostringstream strStream;
strStream << __FUNCTION__ << " ";
if ( fopen_s( &png.fp, m_strFilenameWithPath.c_str(), "rb" ) != 0 ) {
strStream << "can not open file for reading";
throwError( strStream );
}
// Test If File Is Actually A PNG Image
const int NUM_HEADER_BYTES = 8;
png_byte headerBytes[NUM_HEADER_BYTES];
// Read The File Header
if ( fread( headerBytes, 1, NUM_HEADER_BYTES, png.fp ) != NUM_HEADER_BYTES ) {
strStream << "error reading header";
return false;
}
// Test Header
if ( png_sig_cmp( headerBytes, 0, NUM_HEADER_BYTES ) != 0 ) {
return false; // Not A PNG FILE
}
// Init PNG Read Structure - Test PNG Version Compatibility
png.pStruct = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
if ( NULL == png.pStruct ) {
strStream << "can not create struct for PNG file";
throwError( strStream );
}
// Init PNG Info Structure - Allocate Memory For Image Info
png.pInfo = png_create_info_struct( png.pStruct );
if ( NULL == png.pInfo ) {
strStream << "can not create info for PNG file";
throwError( strStream );
}
// Prepare For Error Handling
if ( setjmp( png_jmpbuf( png.pStruct ) ) ) {
strStream << "can not init error handling for PNG file";
throwError( strStream );
}
// Tell libPng Where The File Data Is
png_init_io( png.pStruct, png.fp );
// Tell libPng That You Have Already Read The Header Bytes
png_set_sig_bytes( png.pStruct, NUM_HEADER_BYTES );
// Read Image Data From The File
png_read_png( png.pStruct, png.pInfo, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_GRAY_TO_RGB, NULL );
// Show Image Attributes
png_byte colorType = png_get_color_type( png.pStruct, png.pInfo );
switch( colorType ) {
case PNG_COLOR_TYPE_RGB:
case PNG_COLOR_TYPE_RGBA: {
break;
}
default: {
strStream << "PNG is saved in an unsupported color type (" << colorType << ")";
throwError( strStream );
}
}
unsigned uHeight = png_get_image_height( png.pStruct, png.pInfo );
unsigned uBytesPerRow = png_get_rowbytes( png.pStruct, png.pInfo );
if ( 0 == uHeight || 0 == uBytesPerRow ) {
strStream << "invalid image size. Height(" << uHeight << "), Bytes per row(" << uBytesPerRow << ")";
throwError( strStream );
}
// Make Room For All Pixel Data
unsigned uTotalNumBytes = uHeight * uBytesPerRow;
pTexture->vPixelData.resize( uTotalNumBytes );
// Get All Pixel Data From PNG Image
png_bytepp ppPixelRow = png_get_rows( png.pStruct, png.pInfo );
for ( unsigned int r = 0; r < uHeight; ++r ) {
memcpy( &pTexture->vPixelData[ uBytesPerRow * ( uHeight - 1 - r ) ], ppPixelRow[r], uBytesPerRow );
}
// Store Other Values In Texture
pTexture->uWidth = png_get_image_width( png.pStruct, png.pInfo );
pTexture->uHeight = uHeight;
pTexture->hasAlphaChannel = ( colorType == PNG_COLOR_TYPE_RGBA );
return true;
} // loadPng
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With