PNG 位扩展

PNG Bit extension

我正在编写 PNG 解码器,但我在处理位深度 < 8 的灰度图像时遇到问题。

我不确定如何获得完整的色彩范围。

例如,假设图像使用 4 位深度,数据字节为:10110010 我有 2 个像素,10110010。现在,我将第二个像素向左移动 4 位以占据高位。这就是问题所在。我应该复制位以使 2 个像素为 1011101100100010,还是应该只扩展最后一位以使像素为 1011111100100000。我在 PNG 规范中找不到关于此的信息。

为什么这会出现在规范中?您正在转换输出值,规范不应该关心您对输出数据做了什么。不过,正如 Glenn Randers-Pehrson 观察到的那样,official specification contains relevant advice. Concepts: 4.3.6 Sample depth scaling introduces the basics. Recommendations for encoders and decoders are discussed in 12.5 Sample depth scaling for encoders (scaling external data to a supported PNG format), and 13.12 Sample depth rescaling 用于解码器(将 PNG 格式缩放为所需的输出格式)。

也就是说,假设你想将一个4位的值1111线性转换为一个8位的值1111.1111,那么公式就是

output = 255 * input / 15

将公式应用于范围 0..15,您得到

 0: 0000 -> 00000000
 1: 0001 -> 00010001
 2: 0010 -> 00100010
 3: 0011 -> 00110011
 4: 0100 -> 01000100
 5: 0101 -> 01010101
 6: 0110 -> 01100110
 7: 0111 -> 01110111
 8: 1000 -> 10001000
 9: 1001 -> 10011001
10: 1010 -> 10101010
11: 1011 -> 10111011
12: 1100 -> 11001100
13: 1101 -> 11011101
14: 1110 -> 11101110
15: 1111 -> 11111111

如你所见,前四位总是在低位重复。 正是上面公式的作用!

  255 * input / 15
= input * 255 / 15
= input * 17
= input + input * 16

我们最终得到

output = (input<<4) + input

这可以扩展到上采样(和下采样)任何值到另一个基数:

newvalue = (oldvalue * max_new) / max_old

由于 max_new 通常对于位值来说是奇数,为了获得正确的舍入,您可以使用

newvalue = (2 * oldvalue * max_new + max_old) / (2*max_old)