PNG文件中sBIT块的目的是什么?

5

实际上,我不理解PNG文件中sBIT块的用途。

我正在存储从11位/通道RGB源生成的PNG文件,所以我在我的(c)代码中认真设置了sBIT块:

...
png_color_8 sig_bit;

sig_bit.gray = 0;
sig_bit.alpha = 0;
sig_bit.red = 11;
sig_bit.green = 11;
sig_bit.blue = 11;

png_set_sBIT(png_ptr, info_ptr, &sig_bit);
...
/* save the png */

当使用Windows视图器(本地Vista图片浏览器/Paint.net)查看图片时,低8位会被截断,所以我只能看到高3位。我原以为sBIT块会自动指示读取器将像素左移5位,以便将数据对齐到MSB显示。但事实似乎并非如此。
当我在代码中打开具有或不具有sBIT块的png文件,并执行以下操作:
png_color_8p sig_bit;
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) {
    png_get_sBIT(png_ptr, info_ptr, &sig_bit);
    png_set_shift(png_ptr, sig_bit);
}

像素数据是相同的。
sBIT块的使用模型是什么?我是否可以以某种方式使用sBIT块来将像素数据左对齐以进行查看,但在数字分析中查看“原始”数据?

IHDR块中指定的位深度是多少?sBIT不允许超过该值;如果您没有使用16位的位深度,那么可能就是这个原因导致它不能按照您的意图工作。 - Michael Madsen
@MichaelMadsen 16:我使用png_set_IHDR(img->p,img->i,width,height,16,PNG_COLOR_TYPE_RGB,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);设置了IHDR。 - Jamie
基于您发布的链接,我不得不想知道:sBIT块是否只是提供位掩码的一种方式? - Jamie
2个回答

5

sBIT块告诉解码器像素数据中有多少个有效位。实际上,它告诉解码器数据已经左移以适应标准位深度。例如,对于11位数据的情况,您应该将像素向左移动5位并将其存储为每像素16位。解码器将看到每种颜色中的16位中只有前11位是有效的,因此它可以在知道16位中只有11个有用位的情况下,可能会重新压缩图像以新格式。


1
好的...那么我该如何读取数据呢?png_set_shift()似乎是左移,pnglib API中是否有右移函数? - Jamie
1
如果您有一个格式正确的PNG文件,您应该能够忽略sBIT块并且仍然可以正确显示图像,因为位已经被移位。我编写了自己的PNG编解码器,所以我不知道pnglib的任何信息。关键是像素数据需要事先正确形成,而sBIT块只是解码器的提示,如果它想要了解更多细节。 - BitBank
1
当在读取文件之前调用png_set_shift()时,libpng将对数据进行右移。执行此操作的函数是png_do_unshift()。(不幸的是,这是它所能做的全部,这使我无法将8位数据转换为4位打包) - Cross_

0

您的源具有11位深度,并且您正在创建一个16位深度的PNG图像。因此,您应该将位从最高有效位到最低有效位设置为:MSBXXXX XXXX XXX0 0000LSB2,其中11个X来自源。

解码器不需要关注块以显示 创建的图像,因为在11位深度下,XXX XXXX XXXX2和16位深度下的XXXX XXXX XXX0 00002是相同的值。

要提取源位,您需要将位右移(16-11sBIT)。注意:libpng会在读取图像数据之前使用png_set_shift() sBIT来完成此任务;或者使用带有PNG_TRANSFORM_SHIFT标志的png_read_png()。好吧,回答这个问题:那就是目的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接