libpng 源码的使用 第三节:读 (续2)

接上一节

libpng 源码的使用 第三节:读 (续1)

screen_gamma的值与png_set_gamma的参数相同;然而,

它如何影响输出取决于模式。png_set_alpha_mode()设置文件gamma默认值为1/screen_gamma,所以通常你不需要调用png_set_gamma。如果你需要不同的默认值,在png_set_alpha_mode()之前调用png_set_gamma()——如果你在png_set_alpha_mode()之后调用它,它将覆盖png_set_alpha_mode()所做的设置。

模式如下

PNG_ALPHA_PNG:数据根据PNG规范进行编码。红色、绿色和蓝色或灰色组件是伽马编码的颜色值,并且不会预先乘以alpha值。alpha值是像素对相应的最终输出像素的贡献的线性度量。

如果你想对颜色值进行颜色校正,通常应该使用这种格式;大多数,也许是所有的,颜色校正软件没有处理alpha通道,无论如何,处理预先相乘的组件值的数学是不必要的复杂。

在对组件值进行任何算术运算之前 删除gamma编码并乘以alpha 渠道。 有关更多详细信息,请参见PNG规范。 重要的是要注意,当具有Alpha通道的图像是 标度,线性编码,预乘分量值必须 使用!

其余模式假定您不需要进行任何进一步的色彩校正,或者如果您这样做,您的色彩校正软件将了解有关alpha的全部信息(可能不需要!)。通过存储已按alpha缩放的颜色通道值,它们将alpha与颜色信息“关联”。这优点是可以对颜色通道进行重新采样(图像可以按比例缩放)。缺点是通常的做法是存放线性(非(伽玛)编码的)值,这需要16位通道静止图像而不是8通道,如果使用伽玛编码。除了所有非透明像素值,包括完全不透明的图片,必须经过伽玛编码才能生成最终的图像。这些是“标准”,“关联”或“预乘”模式如下所述(后者是关联的Alpha的两个通用名称颜色通道)。请注意,PNG文件始终包含不相关的颜色渠道;具有其中一种模式的png_set_alpha_mode()会导致解码器将像素转换为关联的表单,然后再将其返回给您应用。

由于没有必要对不透明的颜色值执行算术运算,因此只要它们不被重新采样并且在最终色彩空间中,它就是通过将不透明像素存储在其中可以优化Alpha的处理PNG格式(针对输出色彩空间进行了调整),同时部分存储标准,线性格式的不透明像素。 所需的精度标准alpha成分相对较低,因为像素是隔离的,因此通常会损失存储8位线性信号的精度值是可以接受的。 (如果Alpha通道用于模拟大区域的透明度-在其中使用16位或PNG模式这种情况下!)这是“优化”模式。 在此模式下,像素为仅当alpha值等于最大值时,才将其视为不透明。

PNG_ALPHA_STANDARD:libpng产生的数据编码为最正确编写的图形软件采用的标准方法。gamma编码将被libpng删除,并且线性分量值将预先乘以Alpha通道。

使用这种格式,必须将最终图像重新编码为在显示图像之前匹配显示的伽玛值。如果您的系统没有执行此操作,但仍然可以在不解码的情况下对像素执行算术运算,它已损坏-请查看以下模式。

使用PNG_ALPHA_STANDARD时libpng总是产生线性组件值,无论您提供什么screen_gamma。 这但是,screen_gamma值用作以下项的默认值:如果PNG文件没有Gamma信息,则为文件Gamma。

如果您在png_set_alpha_mode()之后调用png_set_gamma(),将覆盖线性编码。 相反,预乘的像素值将进行伽玛编码,但Alpha通道将仍然是线性的。 这可能实际上符合某些损坏的软件的要求,但这是不可能的。

虽然经常使用线性8位数据,但它具有对于合理的图像,精度不足动态范围。为避免问题,以及您的软件支持它,使用png_set_expand_16()强制所有分量为16位。

    PNG_ALPHA_OPTIMIZED:此模式与PNG_ALPHA_STANDARD相同除了完全不透明的像素根据screen_gamma值。 Alpha小于1.0的像素仍将具有线性分量。

如果您可以控制自己的格式,请使用此格式合成软件,所以不要做其他算术运算(例如缩放)从libpng获取的数据。你的合成软件可以简单地将不透明像素复制到输出,但仍具有线性值非透明像素。

在普通合成中,alpha通道在其中进行编码部分像素覆盖(相对于大面积)半透明),即8位的错误非透明像素的表示形式无关紧要。

如果您的软件损坏,也可以尝试这种格式。它可能看起来更好。

PNG_ALPHA_BROKEN:这是PNG_ALPHA_STANDARD; 但是,所有分量值(包括alpha通道)都经过了伽玛编码。 这样做是无效的,因为在实践中,没有任何使用此选项的实现能够在处理alpha合成之前正确地撤消编码。 仅当您使用的软件或硬件中的其他严重错误要求使用此选项时,才使用此选项。在大多数情况下,软件或硬件损坏时,最终显示中的错误会表现为图像合成部分周围的细微光晕。您甚至可能不会认为这是光环; 图像的合成部分可能会与背景分开显示,就好像它是从纸张上切下然后粘贴到纸上一样。

如果您不必处理软件或硬件中的错误,或者可以解决它们,则建议使用三种方法来使用png_set_alpha_mode():

   png_set_alpha_mode(png_ptr, PNG_ALPHA_PNG,  screen_gamma);

您可以对结果进行颜色校正(libpng当前内部不支持颜色校正)。 处理Alpha通道时,需要撤消gamma编码并乘以Alpha。

   png_set_alpha_mode(png_ptr, PNG_ALPHA_STANDARD,screen_gamma);
   png_set_expand_16(png_ptr);

如果您使用的是高级界面,请不要调用png_set_expand_16(); 而是将PNG_TRANSFORM_EXPAND_16传递到接口。

使用此模式,您无法进行颜色校正,但无需进一步处理即可对数据进行算术运算,包括合成和缩放。

png_set_alpha_mode(png_ptr, PNG_ALPHA_OPTIMIZED,screen_gamma);

您可以使用这种模式避免扩展到16位分量,但是您失去了缩放图像或执行其他线性算术的能力。 您所要做的就是将结果组合到匹配的输出中。 由于此模式是特定于libpng的,因此您还需要编写自己的撰写软件。

以下是对png_set_alpha_mode进行调用的示例,以实现所需的整体伽玛校正,并在必要时实现Alpha预乘。

 png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);

选择透明模式


    PNG_ALPHA_PNG           0 /* according to the PNG standard */
    PNG_ALPHA_STANDARD      1 /* according to Porter/Duff */
    PNG_ALPHA_ASSOCIATED    1 /* as above; this is the normal practice */
    PNG_ALPHA_PREMULTIPLIED 1 /* as above */
    PNG_ALPHA_OPTIMIZED     2 /* 'PNG' for opaque pixels, else 'STANDARD' */
    PNG_ALPHA_BROKEN        3 /* the alpha channel is gamma encoded */

PNG_ALPHA_PNG是Alpha通道的默认libpng处理。 它不会预乘到颜色分量中。 此外,该调用还指出输出是针对sRGB系统的,并导致所有不带gAMA块的PNG文件都假定为使用sRGB编码。

png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC);

在这种情况下,假定输出为类似sRGB的显示,然后是功率为1.45的幂律查找表。 这就是早期Mac系统的表现。

png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_GAMMA_LINEAR);

这是经典的吉姆·布林(Jim Blinn)方法,将在书中所有内容都可以完成的学术环境中工作。 它具有以下假设:没有伽玛信息的输入PNG数据是线性的-除非PNG文件是在本地生成的,否则这不太可能是正确的。 大多数时候,输出精度会很低,以至于在图像的暗区中显示出明显的条纹。

png_set_expand_16(pp);
    png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_DEFAULT_sRGB);

这是吉姆·布林(Jim Blinn)启发的更为现实的方法。 如果未用Gamma值标记,则假定PNG文件具有sRGB编码,并且每个组件的输出始终为16位。 这样可以精确缩放和处理数据。 如果您知道输入的PNG文件是在本地生成的,则可能需要将PNG_DEFAULT_sRGB替换为系统的正确值。

    png_set_alpha_mode(pp, PNG_ALPHA_OPTIMIZED, PNG_DEFAULT_sRGB);

如果您只需要将PNG图像合成到现有背景上,并且控制了执行此操作的代码,则可以使用优化设置。 在这种情况下,您只需将完全不透明的像素复制到输出中。 对于不是完全透明的像素(您只是跳过这些像素),可以使用下面的png_composite或png_composite_16进行合成数学,然后对结果的8位或16位值进行编码以匹配输出编码。

其他情况

如果由于您使用的软件或硬件,PNG和标准线性编码都不适合您,那么您将遇到很大的问题。 PNG情况可能会导致图像周围出现光晕。 线性编码可能会导致褪色,太亮的图像(实际上太对比度)。请尝试上面的ALPHA_OPTIMIZED模式-这可能会大大减少光晕。 或者尝试:

png_set_alpha_mode(pp, PNG_ALPHA_BROKEN, PNG_DEFAULT_sRGB);

此选项还可以减少光晕,但是在背景较浅的图像不透明部分周围会出现轻微的深色光晕。 在优化模式下,光晕为浅光晕,背景为暗色。 选择-除非您能够修复硬件/软件,否则不可避免地会出现光环! (优化方法要快一些。)

当PNG文件的默认灰度系数与输出灰度系数不匹配时。 如果您的PNG文件没有伽玛信息,则png_set_alpha_mode允许您提供默认的伽玛,但也会将输出伽玛设置为匹配值。 如果您知道您的PNG文件的伽玛与输出不匹配,则可以利用以下事实:png_set_alpha_mode始终设置输出伽玛,但仅设置尚未设置的PNG默认值:

    png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);
    png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC);

第一个调用会同时设置默认Gamma值和输出Gamma值,
第二个调用将覆盖输出灰度系数,而不更改默认值。 这比使用png_set_gamma获得相同的效果容易。 您必须为第一次调用使用PNG_ALPHA_PNG-如果在同一读取操作中对png_set_alpha_mode和png_set_background进行了多次调用,则将触发png_set_alpha的内部检查,但是将忽略多次使用PNG_ALPHA_PNG的调用。

如果不需要或无法处理Alpha通道,则可以调用png_set_background()通过与固定颜色进行合成来将其删除。 不要调用png_set_strip_alpha()来执行此操作-它将在此图像的透明部分中留下虚假像素值。

   png_set_background(png_ptr, &background_color, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1);

根据libpng将为您生成的数据格式,background_color是RGB或灰度值。 因为你还不知道的PNG文件的格式,如果你在这一点上叫png_set_background你必须安排通过了libpng总是有8位或16位的组件,然后颜色存储为一个生成的格式8- 位或16位颜色(视情况而定)。 颜色包含单独的灰度和RGB分量值,因此您可以让libpng根据输入格式生成灰度或RGB输出,但是低位深度灰度图像必须始终转换为至少8位格式。 (即使低位深度灰度图像不能具有Alpha通道,它们也可以具有透明颜色!)

您可以设置以后需要的转换,或者将其设置为高级接口的标志,或者将其作为低级接口的libpng API调用。 作为参考,所需的设置和API调用为:

8-bit values:
   PNG_TRANSFORM_SCALE_16 | PNG_EXPAND
   png_set_expand(png_ptr); png_set_scale_16(png_ptr);

  如果您必须获得与libpng-1.5.4之前的版本中默认情况下产生的完全相同的不准确结果,请改用PNG_TRANSFORM_STRIP_16和png_set_strip_16(png_ptr)。

16-bit values:
   PNG_TRANSFORM_EXPAND_16
   png_set_expand_16(png_ptr);

无论哪种情况,调色板图像数据都将扩展为RGB。 如果只需要颜色数据,则可以将PNG_TRANSFORM_GRAY_TO_RGB或png_set_gray_to_rgb(png_ptr)添加到列表中。

在读取PNG文件头之前调用png_set_background在libpng-1.5.4之前不起作用。 由于故障可能导致意外的警告或错误,因此在读取磁头之后调用png_set_background更加安全。 不幸的是,这意味着在libpng-1.5.4之前,它不能与高级接口一起使用。

上层读取接口(用户主要使用的接口)

猜你喜欢

转载自blog.csdn.net/catshit322/article/details/114745924