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

接上一篇

libpng 源码使用和手册机器翻译 第三节:读

Unknown-chunk 处理

现在可以设置库在输入PNG流中处理未知块的方式。已知和未知的块都将被读取。正常的行为是已知的块将被解析成info_ptr成员中的信息,而未知的块将被丢弃。如果您的应用程序从未使用过某些已知的块类型,那么这种行为可能是一种浪费。要改变这一点,你可以调用:

    png_set_keep_unknown_chunks(png_ptr, keep,
        chunk_list, num_chunks);

   /* keep       - 0: default unknown chunk handling
                 1: ignore; do not keep
                 2: keep only if safe-to-copy
                 3: keep even if unsafe-to-copy

               You can use these definitions:
                 PNG_HANDLE_CHUNK_AS_DEFAULT   0
                 PNG_HANDLE_CHUNK_NEVER        1
                 PNG_HANDLE_CHUNK_IF_SAFE      2
                 PNG_HANDLE_CHUNK_ALWAYS       3

    chunk_list - list of chunks affected (a byte string,
                 five bytes per chunk, NULL or '\0' if
                 num_chunks is positive; ignored if
                 numchunks <= 0).

    num_chunks - number of chunks affected; if 0, all
                 unknown chunks are affected.  If positive,
                 only the chunks in the list are affected,
                 and if negative all unknown chunks and
                 all known chunks except for the IHDR,
                 PLTE, tRNS, IDAT, and IEND chunks are
                 affected.
*/

以这种方式声明的未知块将作为原始数据保存到png未知块结构的列表中。如果一个通常为libpng所知的块在列表中被命名,根据“keep”指令,它将被处理为未知的。如果一个块在 png_set_keep_unknown_chunks()的连续实例中命名,最后一个实例将优先。IHDR和IEND块不应该在块列表中命名;如果是,libpng将正常处理它们。如果您知道您的应用程序永远不会使用某些特定块,请使用PNG_HANDLE_CHUNK_NEVER(或1),如下所示。

下面是一个使用png_set_keep_unknown_chunks()的例子,其中私有的“vpAg”块将稍后由用户块回调函数处理:

 png_byte vpAg[5]={118, 112,  65, 103, (png_byte) '\0'};

    #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
      png_byte unused_chunks[]=
      {
        104,  73,  83,  84, (png_byte) '\0',   /* hIST */
        105,  84,  88, 116, (png_byte) '\0',   /* iTXt */
        112,  67,  65,  76, (png_byte) '\0',   /* pCAL */
        115,  67,  65,  76, (png_byte) '\0',   /* sCAL */
        115,  80,  76,  84, (png_byte) '\0',   /* sPLT */
        116,  73,  77,  69, (png_byte) '\0',   /* tIME */
      };
    #endif

    ...

    #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
      /* ignore all unknown chunks
       * (use global setting "2" for libpng16 and earlier):
       */
      png_set_keep_unknown_chunks(read_ptr, 2, NULL, 0);

      /* except for vpAg: */
      png_set_keep_unknown_chunks(read_ptr, 2, vpAg, 1);

      /* also ignore unused known chunks: */
      png_set_keep_unknown_chunks(read_ptr, 1, unused_chunks,
         (int)(sizeof unused_chunks)/5);
    #endif

用户限制

PNG规范允许图像的宽度和高度为2^31-1 (0x7fffffff),或约2.147亿行和列。为了安全起见,libpng默认限制为100万行和列。较大的图像将立即被拒绝,并调用png error()。如果你想改变这些限制,你可以使用

 png_set_user_limits(png_ptr, width_max, height_max);

设置您自己的限制(libpng可能会因为潜在的缓冲区溢出条件而拒绝一些非常宽的图像)。

您应该在创建PNG结构之后,在调用png_read_info()、png_read_png()或png_process_data()之前放置此语句。

当写一个PNG数据流时,把这个语句放在调用png_write_info()或png_write_png()之前。

如果您需要检索所应用的限制,请使用

   width_max = png_get_user_width_max(png_ptr);
   height_max = png_get_user_height_max(png_ptr);

PNG规范对PNG数据流中允许的辅助块数量没有限制。默认情况下,libpng强加了一个限制总共有1000 个sPLT、tExt、iTxt、zTXt和未知的块要存储。如果info_ptr和end_info_ptr都设置了,那么限制将分别应用于它们。您可以更改将存储的此类块总数的限制,使用

   png_set_chunk_cache_max(png_ptr, user_chunk_cache_max);

ex7fffffffL表示无限。你可以用

   chunk_cache_max = png_get_chunk_cache_max(png_ptr);

Libpng对除IDAT之外的任何块可以占用的内存量施加了8兆(8,000,000字节)的限制,无论是最初还是解压缩时(在Libpng -1.6.32之前,这个限制只适用于解压缩后的压缩块)。你可以使用下面语句修改这个极限

   png_set_chunk_malloc_max(png_ptr, user_chunk_malloc_max);

可以用

   chunk_malloc_max = png_get_chunk_malloc_max(png_ptr);

获取限制。

任何会导致超出这些限制的块都将被忽略。

你系统的信息

如果您想要显示PNG或将其合并到其他图像数据中,您需要告诉libpng关于您的显示或绘图表面的信息,以便libpng可以转换图像中的值以匹配显示。

在libpng-1.5.4中,可以在读取PNG文件头之前设置此信息。在早期版本中,png_set_gamma()存在,但如果在PNG文件头被读取之前调用,且png_set_alpha_mode()不存在,则表现不正确。

如果您需要支持LIBPNG -1.5.4之前的版本,请使用“PNG LIBPNG VER >= 10504”测试版本号,并遵循相应手册页中描述的步骤。

您为libpng提供了系统预期的编码,表示为'gamma值'。还可以为PNG文件指定一个默认编码如果文件中缺少所需的信息。默认情况下,libpng假设PNG数据与你的系统匹配,为了保持这个默认调用:

   png_set_gamma(png_ptr, screen_gamma, output_gamma);

或者你也可以使用定点:

   png_set_gamma_fixed(png_ptr, PNG_FP_1*screen_gamma,
      PNG_FP_1*output_gamma);

如果你不知道你的系统的伽玛,它可能是2.2 -一个很好的接近IEC显示系统标准(sRGB)。如果图像的对比度太强或被冲淡,那么你就得到了错误的值-检查你的系统文档!!

许多系统允许通过显示驱动程序中的查找表更改系统gamma,一些系统,包括旧的mac,通过lefault更改响应。从1.5.4开始,有三个特殊的值可以处理常见的情况:

   PNG_DEFAULT_sRGB: 表示该系统符合IEC 61966-2-1标准。这几乎适用于所有系统。
   PNG_GAMMA_MAC_18: 表示该系统是较旧的(Mac os 10.6之前)苹果Macintosh系统,使用默认设置。
   PNG_GAMMA_LINEAR: 就是1的定点值。表示系统没有伽马编码的数据。

如果需要进一步处理像素值,您可以使用线性(未编码)值,因为这避免了在执行算术时需要解码和重新编码每个组件值。由于这个原因,许多图形软件使用线性值,往往与更高精度的组件值,以保持整体精度。

输出值表示如何解码输出值,而不是如何编码。所使用的值对应于用于描述计算机显示系统的总体伽马的正常值;例如,sRGB系统的2.2版本。在API的固定版本中,该值被放大了100000 (sRGB为220000)。

如果没有伽马数据块,并且png_set_gamma()没有被调用来覆盖PNG伽马信息,则该值的倒数总是用来为PNG文件编码提供一个默认值。

当选择 ALPHA_OPTIMIZED 模式时,输出伽玛将用于编码不透明像素,然而,无论输出伽玛设置如何,alpha 值(透明度)较低的像素都不会被编码。

当要求使用模式1的标准 Porter Duff 处理时,输出编码被设置为线性的,并且output_gamma值仅相关默认为没有伽马信息的输入数据。如果调用了png_set_gamma(),线性输出编码将被覆盖——结果可能非常出乎意料!

以下数据来源于sRGB标准及其背后的研究。sRGB被定义为PNG的伽马块值为0.45455(1/2.2)。该值隐含地包括考虑到原始场景和预期显示环境的颜色环境的任何差异而需要的任何观看校正;该值表示如何解码图像以显示,而不是如何对原始数据进行编码。

sRGB通过定义一个查看环境为PNG标准提供了一个peg。sRGB本身,以及早期的电视标准,实际上使用了比PNG更复杂的变换(一个比γ 2.4幂律更线性的部分)。(PNG受限于简单的幂律。)通过说在符合sRGB的系统上直接显示的图像应该以gAMA块值45455存储(ISO PNG规范的11.3.3.2和11.3.3.5),PNG规范使获得其他显示系统和环境的值成为可能。

Mac值是根据sRGB推导出来的,这是基于一个假设,即早期Mac显示系统中使用的实际额外观看校正是作为power 1.45查找表实现的。

任何使用可编程查找表或可以改变最终显示设备特征的行为的系统都需要系统特定的代码来获得当前的特征。然而,这可能是困难的,大多数PNG gamma校正只需要一个近似的值。

默认情况下,如果没有调用png_set_alpha_mode(), libpng假设所有的值都是未编码的线性值,并且输出设备也具有线性特征。这很少是正确的——如果你不知道正确的答案是什么,使用PNG_DEFAULT_sRGB调用png_set_alpha_mode()总是比依赖于默认值更好!

特殊值PNG_GAMMA_MAC_18表示较老的Mac系统(pre Mac OS 10.6),该系统使用修正表在sRGB系统上实现较低的gamma值。

这两个值都保留了(不是简单的伽玛值),以便将来在内部进行更精确的校正。

注意:这些值可以传递给固定或浮点API,但是浮点API也接受浮点值。

您可能需要告诉libpng的第二件事是您的系统如何处理alpha通道信息。一些,但不是所有,PNG文件包含一个alpha通道。要正确地显示这些文件,需要将数据组合到合适的背景上,PNG规范中有描述。

Libpng只支持组合成单一颜色(使用png_set_background;见下文)。否则,你必须自己进行组合,在这种情况下,你可能需要调用png_set_alpha_mode:

   #if PNG_LIBPNG_VER >= 10504
      png_set_alpha_mode(png_ptr, mode, screen_gamma);
   #else
      png_set_gamma(png_ptr, screen_gamma, 1.0/screen_gamma);
   #endif

暂时 翻译到835行 待续

猜你喜欢

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