我正在尝试使用C#以每通道16位(bpc)的灰度图像解码PNG。我相信我正在解码正确的原始值,但是当我转换为8bpc返回值时,我没有计算与System.Drawing
,Gimp或SixLabors.ImageSharp
相同的值。
给出单个灰度像素的以下字节值:
byte b0 = data[index];
byte b1 = data[index + 1];
我尝试了以下映射:
byte result = b0;
byte result = (byte)(255 * (((b0 << 8) + b1)/ushort.MaxValue));
byte result = (byte)(((b0 << 8) + b1)/256.0);
但是这些方法似乎都不符合其他软件预测的以下值:
b0 b1 expected
55 186 55
67 135 67
35 241 36
我确定我误解了归一化为8 bpc值的正确方法。
有问题的图像是这样的:
答案 0 :(得分:1)
以下是转换位深度的官方方法:
https://www.w3.org/TR/2003/REC-PNG-20031110/#13Sample-depth-rescaling
output = floor((input * MAXOUTSAMPLE / MAXINSAMPLE) + 0.5)
where
MAXINSAMPLE = (2^sampledepth)-1
MAXOUTSAMPLE = (2^desired_sampledepth)-1
所以,如果我以您的最后一个例子为例:
35 << 8 | 241 == 8960 | 241 == 9201
9201 * 255 / 65535 == 2346255 / 65535 == 35
floor(35 + 0.5) == 35
为什么不36
?
There might gamma being involved。
结论:
首先检查您的内部实现是否正确遵循规范,然后进行相应调整。