PNG 位扩展
PNG Bit extension
我正在编写 PNG 解码器,但我在处理位深度 < 8 的灰度图像时遇到问题。
我不确定如何获得完整的色彩范围。
例如,假设图像使用 4 位深度,数据字节为:10110010
我有 2 个像素,1011
和 0010
。现在,我将第二个像素向左移动 4 位以占据高位。这就是问题所在。我应该复制位以使 2 个像素为 10111011
和 00100010
,还是应该只扩展最后一位以使像素为 10111111
和 00100000
。我在 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)
我正在编写 PNG 解码器,但我在处理位深度 < 8 的灰度图像时遇到问题。
我不确定如何获得完整的色彩范围。
例如,假设图像使用 4 位深度,数据字节为:10110010
我有 2 个像素,1011
和 0010
。现在,我将第二个像素向左移动 4 位以占据高位。这就是问题所在。我应该复制位以使 2 个像素为 10111011
和 00100010
,还是应该只扩展最后一位以使像素为 10111111
和 00100000
。我在 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)