无法在 Linux 上读取 DDS 映像标头
Can't read DDS image header on Linux
我使用Nvidia nv_dds实用程序来加载DDS图像文件以在OpenGL程序中使用。它在Windows上工作,但在Linux (Ubuntu 12.10)上失败。最初我认为nv_dds的问题,但后来发现fread()读取头字节与错误的偏移在Linux (GCC 4.7)
这是读取DDS文件标记和DDS头的块:
// open file
FILE *fp = fopen(filename.c_str(),"rb");
if (fp == NULL) {
return false;
}
// read in file marker, make sure its a DDS file
char filecode[4];
fread(filecode, 1, 4, fp);
if (strncmp(filecode, "DDS ", 4) != 0) {
fclose(fp);
return false;
}
// read in DDS header
DDS_HEADER ddsh;
fread(&ddsh, 1,sizeof(DDS_HEADER) , fp);
当我查看DDS_HEADER实例的内容时,我可以看到几个分配给错误属性的真实值,其余的都是垃圾。
然后,如果我注释掉"DDS"标记检查读取():
// open file
FILE *fp = fopen(filename.c_str(), "rb");
if (fp == NULL) {
return false;
}
// read in file marker, make sure its a DDS file
/* comment out for test
char filecode[4];
fread(filecode, 1, 4, fp);
if (strncmp(filecode, "DDS ", 4) != 0) {
fclose(fp);
return false;
}
*/
// read in DDS header
DDS_HEADER ddsh;
fread(&ddsh, sizeof( DDS_HEADER ),1 , fp);//sizeof( DDS_HEADER )
然后我得到图像宽度值到DDS_HEADER的imageHeight属性。其余的属性仍然是垃圾。
当我在Windows机器上测试时,所有这些都没有发生。是否有可能在Linux GCC上与使用MSVC编译器的Windows上工作不同?
我解决了这个问题,因为没有提出有用的输入,所以我将自己回答这个问题。
我开始怀疑不同编译器之间数据类型大小的差异。然后我发现了这个帖子。在那之后,我发现DDS头的大小(用GCC编译)是248,比它应该大两倍。(微软的规格说它必须恰好是124字节)。Nv_dds DDS头的成员使用unsigned long:
typedef struct
{
unsigned long dwSize;
unsigned long dwFlags;
unsigned long dwHeight;
unsigned long dwWidth;
unsigned long dwPitchOrLinearSize;
unsigned long dwDepth;
unsigned long dwMipMapCount;
unsigned long dwReserved1[11];
DDS_PIXELFORMAT ddspf;
unsigned long dwCaps1;
unsigned long dwCaps2;
unsigned long dwReserved2[3];
}DDS_HEADER;
所以看起来MSVC编译器将unsigned long处理为4字节,而Linux上的GCC处理为8字节。从这里是标题的两倍大小。我将其全部更改为unsigned int(也在DDS_PIXELFORMAT头文件中):
typedef struct
{
unsigned int dwSize;
unsigned int dwFlags;
unsigned int dwHeight;
unsigned int dwWidth;
unsigned int dwPitchOrLinearSize;
unsigned int dwDepth;
unsigned int dwMipMapCount;
unsigned int dwReserved1[11];
DDS_PIXELFORMAT ddspf;
unsigned int dwCaps1;
unsigned int dwCaps2;
unsigned int dwReserved2[3];
}DDS_HEADER;
现在一切正常了!因此,看起来,与某些地方所说的相反,NVidia nv_dds不是跨平台的(或/和交叉编译读取),这个hack应该做,让它在Linux上与GCC一起工作。
在GCC中,long为32位编译时为4字节,64位编译时为8字节。Use可以使用选项-m32或-m64来明确目标为32位或64位。
对于ABI相关的任务,您应该始终使用在stint .h中定义的类型名称中描述其大小的类型,如int32_t/uint64_t,这可以在不同平台上编译期间节省很多问题。(大/小端序问题除外)
- SDL 映像:无法打开映像,仅显示错误消息
- C++ W:使用子线程的运行映像
- 从头开始为应用程序创建 docker 映像是否有意义?
- 主机箱/bash 未执行 docker 映像
- 无法从Java读取C++中保存的Opencv Mat映像
- CMake链接库在Docker映像中失败
- 在.NET Core 3.1中运行托管C++/CLI程序集时,映像格式错误
- 如何在C++中使用ZeroMQ通信多个映像
- 无法写入映像 SimpleElastix (Python)
- 如何在 windowsservercore Docker 映像上安装执行本机C++ DLL/EXE 所需的所有依赖二进制
- 无法将映像加载到 SDL2 程序
- 从 docker 映像构建中省略安装文件
- 使用 OpenGL 中的 imageStore 写入映像
- QML 映像不会在映像源中加载具有非 ASCII 字符的图像
- 警告在将 OpenCV 垫映像投射到 QImage 时使用旧式转换
- 在控制台上显示 BMP 映像时堆损坏
- 处理映像上的多个转换
- 我可以将带有依赖项的C++库作为 Docker 映像分发吗?
- 如何使用"trusty"映像在本地执行C++程序的Travis CI?
- 无法在 Linux 上读取 DDS 映像标头