我需要做一个简单的检查 dds 文件的格式是否有效。我只需要对 dds 文件进行一般检查,所以我不需要检查它是否是 dxt1、dxt5、dx10 等。例如,如果我有一个 png 图像并且我将扩展名重命名为 .dds dds 格式当然会是错误的,然后我需要告诉用户他正在尝试使用格式错误的 dds 文件。但是,如果我有一个确实具有正确文件格式的 dds,我将不需要做任何进一步的调查,因为我不关心它是什么类型的 dds 文件(此时)。所以我只需要阅读 dds 文件中所有 dds 文件都保持不变的部分。 我想我可以通过某种方式读取 dds 标头和幻数。 我必须对 png 文件进行相同的验证,并且我正在读取 png 标题,如下所示:
var png = new byte[] { 0x89, 0x50, 0x4e, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }
using (FileStream fs = new FileStream(fileToCheck, FileMode.Open, FileAccess.Read))
{
if (fs.Length > buffer.Length)
{
fs.Read(buffer, 0, buffer.Length);
fs.Position = (int)fs.Length - endBuffer.Length;
fs.Read(bufferEnd, 0, endBuffer.Length);
}
fs.Close();
}
for (int i = 0; i < png.Length; i++)
{
if (buffer[i] != png[i])
return false;
}
return true;
我在寻找是否有类似的方法来检查 dds 文件的格式。我对此很陌生,我遇到的问题是知道 dds 文件中的哪些字节对于所有 dds 文件始终相同(以便我可以检查这些字节以查看 dds 格式是否有效)以及我如何可以通过简单的方式实现代码来检查dds格式。任何帮助将不胜感激。
编辑: 所以感谢@NaCl,我已经回答了问题的第一部分。我现在知道 dds 文件中的哪些部分是必需的,但我不知道如何在 dds 文件中找到它。我用十六进制编辑器打开了很多 dds 文件,但我不太擅长逆向工程,所以我不明白我需要检查的字节在哪里,这进一步让我不知道如何实现代码在指定位置搜索字节(我可以用 png 文件来做,因为我发现了更多关于该文件的文档),因为我不知道该去哪个位置。
如果有人能指出我正确的方向或以其他方式帮助我,我将非常感激。谢谢。
对具有标题的文件要做的第一件事是检查其幻数(如果文档中有的话),如果是DDS文件,幻数是
0x44445220
等于 "DDS "
在“纯文本”中。
之后,只需处理规格即可。一切(幻数除外)都以小端格式存储,因此在处理字节时要小心,根据 Microsoft 的说法,DDS 标头的definition 是(C++):
typedef struct {
DWORD dwSize; /* Always equal to 124 */
DWORD dwFlags;
DWORD dwHeight;
DWORD dwWidth;
DWORD dwPitchOrLinearSize;
DWORD dwDepth;
DWORD dwMipMapCount;
DWORD dwReserved1[11];
DDS_PIXELFORMAT ddspf;
DWORD dwCaps;
DWORD dwCaps2;
DWORD dwCaps3;
DWORD dwCaps4;
DWORD dwReserved2;
} DDS_HEADER;
基于此,我为任何“通用”DDS 文件提供了以下代码:
public static bool IsValidDDS(string path)
{
if (path == null)
throw new ArgumentNullException(nameof(path));
if (!File.Exists(path)) // Check for existence.
return false;
uint magicNumber = 0; byte[] headerLength = new byte[sizeof(byte)];
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
byte[] magic = new byte[sizeof(uint)];
// I'm still pretty used to C and fread, so here you go :^)
if (fs.Read(magic, 0, sizeof(uint)) != sizeof(uint))
return false; // Not even a valid file.
if (fs.Read(headerLength, 0, sizeof(byte)) != sizeof(byte))
return false; // Not enough bytes, even if the first 4 bytes were checked.
// Convert to a big endian integer.
magicNumber = (uint)((magic[0] << 24) | (magic[1] << 16) | (magic[2] << 8) | magic[3]);
}
return (headerLength[0] == 0x7C) && (magicNumber == 0x44445320);
}
上面的代码只检查输入文件的前 5 个字节(作为参数传递
path
),它们总是和我看到的一样,应该等于:
0x44 0x44 0x53 0x20 0x7C 0x00 0x00 0x00 (8 bytes)
上面的代码是用这个存储库上的
.dds
文件测试的:https://github.com/toji/webgl-texture-utils/tree/master/sample/img,两个文件都有完全相同的标题:
iamnacl:~/workspace $ cd dds-test/
iamnacl:~/workspace/dds-test $ dotnet run ../test-dxt1.dds
The file is a valid DDS file? True
iamnacl:~/workspace/dds-test $ dotnet run ../test-dxt5.dds
The file is a valid DDS file? True
iamnacl:~/workspace/dds-test $
您可以优化上面的代码以执行一次对
fs.Read
的调用,大小为 ulong
并根据此值检查整个事情:0x444453207C000000
.
希望这有帮助:)
当然这是一篇旧文章(但很有用!)。谁能建议如何调整此脚本以在充满 dds 文件的文件夹上运行? :-)