.net 手动阅读与Windows属性值不匹配的PNG标头的BitDepth

bis0qfac  于 2022-11-19  发布在  .NET
关注(0)|答案(1)|浏览(131)

我想把这个问题放在前面,我只是在玩和学习。我不想使用本机内置方法或外部库来完成这个问题。我也不想以一种更优化的方式来完成它,而这种方式肯定是可以实现的,并在其他类似的问题中描述过。我只想了解我看到了什么,以及为什么当我手动解码头文件时。
简短版本:我试图从二进制格式读取PNG头字节。我似乎总是得到一个值8的位深度,但文件的windows属性显示不同的值(如32,24)。
我还检查了online tool / website显示位深度为8的相同PNG。所以我不认为这是我的代码,我只是不知道windows从哪里得到它,也不知道我应该如何匹配它。
从Windows查看的示例文件显示32位深度,如下所示:

这是我的示例代码(来自LinqPad,但很容易转移到程序)

var rawFileStream = new System.IO.FileStream("c:\\temp\\test2.png", FileMode.Open);
var buffer = new char[4].ToList();
    
while (!IsHeaderInBuffer())
{
    ReadIntoBuffer();
}
    
var width = BitConverter.ToInt32(ReadNBytesAsLittleEndian(4)).Dump();
var height = BitConverter.ToInt32(ReadNBytesAsLittleEndian(4)).Dump();
var bitdepth = ReadSingle().Dump();
var colorType = ReadSingle().Dump();
var compression = ReadSingle().Dump();
var filter = ReadSingle().Dump();
var interlace = ReadSingle().Dump();
    
int ReadSingle()
{
    return rawFileStream.ReadByte();
}
    
byte[] ReadNBytesAsLittleEndian(int n) 
{
    var result = new byte[n];
    for (int i = 0; i < n; i++)
    {
        var b = rawFileStream.ReadByte();
        result[n - i - 1] = (byte)b;
    }
    
    return result;
}
    
void ReadIntoBuffer() 
{
    buffer.Remove(buffer.First());
    buffer.Add((char)rawFileStream.ReadByte());
}
    
bool IsHeaderInBuffer()
{
    var enumerator = "IHDR".GetEnumerator();
   
    return buffer.All(x =>
    {
        enumerator.MoveNext();
        return x == enumerator.Current;
    });
}

以上的输出为:

1197
883
8
6
0
0
0
xtfmy6hx

xtfmy6hx1#

Windows文件属性中显示的BitDepth与PNG格式的位深度不同。
Windows显示的是每像素的总位数(在您的情况下为32,假设您有一个4通道RGBA图像)。
正如您在WikiPedia PNG page中所看到的,PNG头在widthheight之后有2个相关字段:

  • 位深度(1个字节,值为1、2、4、8或16)
  • 颜色类型(1个字节,值为0、2、3、4或6)

即,从PNG的Angular 来看,位深度是单个通道的位数。
您需要将其乘以通道数(基于颜色类型),以获得每像素的总位数,如Windows文件属性中所示。
更新:
您在评论中提到,您的案例中的颜色类型为6。根据means的规格:
每个像素是一个R、G、B三元组,后跟一个Alpha样本。
这意味着您有4个通道,每个通道有8位,因此每个像素的总位数为32,如Windows文件属性中所报告的。

相关问题