无法在 Linux 上读取 DDS 映像标头

Can't read DDS image header on Linux

本文关键字:DDS 映像 读取 Linux      更新时间:2023-10-16

我使用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,这可以在不同平台上编译期间节省很多问题。(大/小端序问题除外)