尝试使用 libpng 加载图像时在 Windows 上出现运行时错误
Runtime error on Windows when trying to load image with libpng
我正在使用pHash,而该库使用libpng。我在运行程序时遇到问题,因为 libpng 加载 PNG 文件失败。
- libpng版本:1.4.19
- 平台: 视窗 10
- 环境:Visual Studio 2015
琐碎
只是如果你想出以下问题...
- 图像路径是否正确?是的
- 图像是否为有效的 PNG 文件?是的
代码详细信息
图书馆 pHash 使用 CImg,我认为他们使用的 CImg 版本有点旧:
#define cimg_version 148 // In CImg.h
我已经调试了库,问题发生在CImg.h
(包含在 pHash VC++ 项目中):
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 availabilityrn");
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*)");
...
}
该代码段显示了CImg<T>& _load_png(std::FILE *const file, const char *const filename)
的第一部分,该部分由 pHash 使用的 CImg 库调用。
运行时问题
代码编译良好,但我在运行时收到此错误,我可以在调试器中看到:
CImgIOException:无法初始化"png_ptr"...
在代码中指示的点。我不知道为什么,加载图像失败。在 CImg.h
中调用 png_create_read_struct
时发生故障。通过预处理器指令定义的该代码有点晦涩难懂。目前尚不清楚它为什么会失败。
有什么想法吗?
如果您自己包含libpng,或者如果另一个库包含并使用libpng,则需要注意一些事项。
- 无论您使用的是哪个版本的 Visual Studio,libpng(dll 或 lib)文件都必须从您的解决方案所链接的同一版本的 Visual Studio 生成。
- 您正在使用的 32 位或 64 位平台值得关注。 生成
- png 库时的项目设置必须与当前项目的生成类型匹配。(代码生成 ->运行时库)必须匹配。您的字符集也应该匹配。
要说到底是什么导致了问题,有点困难,但这些是需要注意的几件事。
我建议的一件事是访问提供最新版本libpng的网站并下载它。在计算机上设置一个文件夹,并创建"通过窗口的系统环境变量"以指向您的库。在您正在使用的当前版本的 VS 中打开此库的解决方案,为静态库和动态库(两种不同的解决方案)构建它,并将它们构建为 32 位和 64 位,将生成的文件保存到单独的文件夹中。然后进入依赖于此的另一个库,并尝试切换 dll 或库,并在可能的情况下链接到新的库。此外,您应该尝试在相同版本的VS中打开其解决方案,并尝试从那里进行干净的构建。然后确保正确链接所有内容。您可能还必须修改 props 文件。
编辑
我不熟悉pHash或CImg,但我熟悉libpng。
这是我的一个项目中的一个函数,用于将 png 加载到纹理结构中。现在这是依赖于许多其他类的类对象的一部分,但您应该能够从此代码段中看到我已成功使用 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
查看源代码以获取png_create_read_struct_2()
,只有 2 种故障模式:无法分配内存(这不太可能是问题)和库版本冲突。
预编译版本,则必须确保在运行时动态链接的 libpng DLL 的副本与编译 pHash 所针对的库版本相同。 pHash.org 上的最新 Windows 版本在"发布"子目录中附带 libpng12.dll,这可能与您在问题中提到的版本(即 1.4.19)不兼容。
如果要从源代码构建 pHash,请确保 libpng 包含构建过程中使用的文件与运行时加载的版本匹配。
如果您不确定在运行时加载了哪些 DLL,那么我知道确定它的最可靠方法是使用进程监视器。
- 删除指向指针的指针是运行时错误吗
- c++中的指针和运行时错误
- 无法理解此 return 语句的功能,没有它就会发生运行时错误
- 在同一模拟中使用静脉和静脉_ inet内容时出现运行时错误
- 对单向链表进行排序时出现运行时错误
- 为什么此代码存在运行时错误?
- 你能解释一下什么运行时错误是如何解决它的吗?
- 为什么会出现 gettnig 运行时错误:加载类型为"_Bit_type"(stl_bvector.h) 的空指针?
- 为什么程序在 c++ 中迭代 emtpy 向量时会抛出运行时错误
- 运行时错误:引用绑定到类型为"int"的空指针
- 为什么当 vector 为空时会显示运行时错误?
- C++运行时错误与快速排序算法抛出堆栈转储错误
- 运行时错误:矢量下标超出范围:正在检查空集
- 分配给gslice_array会导致运行时错误
- cout 新创建的对象引发运行时错误
- C++在使用std::multimap时出现运行时错误的几率很小
- 运行时错误:引用绑定到类型"int"的未对齐地址0xbebebebebebebec6,这需要 4 个字节对齐 (stl_vector.h)
- 从Windows交叉编译的GNU ARM(BeagleBoneBlack)。*.elf 上的运行时错误:"No such file or directory"
- windows运行时-{c++}程序在没有visual Studio的计算机上运行时会发送错误0xc00007b
- 尝试使用 libpng 加载图像时在 Windows 上出现运行时错误