AS问题解决系列3—iCCP: Not recognizing known sRGB profile

1. 问题描述   

    在Android Studio 1.2.2下编译期间,出现了下面警告信息:php

    ...\res\drawable-hdpi\add_green.png: libpng warning: iCCP: Not recognizing known sRGB profile that has been editedhtml

    baidu和google,有一些网友是非png格式的图片(例如jpg格式等)而错误地采用了png为后缀,也会出现上述告警信息,可参见[7],本文不考虑这些状况。linux

    其余网友的回答基本上都是:缘由是新版本的libpng对关于iCCP采用了更严苛的约束。可是是从哪一个libpng版本开始严格检查,主要是检查哪些内容致使的告警信息呢?基本上没有看到答案。android

   本文先学习下PNG文件格式,而后了解下libpng, 再来分析和解决这个警告信息。git

2. PNG文件格式   

     [2]是WWW PNG的规范,[3]是经过例子来介绍PNG文件格式中文编写,下面材料主要来自于这两份文档。github

     每一个PNG文件是由一个PNG标识(signature),后面跟一些数据块(chunk)组成,每一个chunk由一个chunk类型来标识其功能。数组


2.1 PNG标识(signature
maven

    每一个PNG文件的前8个字节老是包含如下值:ide

十进制   137 80 78 71 13 10 26 10
十六进制  89 50 4E 47 0D 0A 1A 0A

    第一个字节0x89超出了ASCII字符的范围,这是为了不某些软件将PNG文件当作文本文件来处理函数

2.2 数据块(chunk)

    在png规范[2]中总计定义了18种chunk,其中4类chunk是关键数据块(critical chunk),每一个PNG文件都必须包含它们,其他14类为辅助数据块(ancillary chunks),这是可选的数据块。

2.2.1 4类关键chunk 

    IHDR: image header, 在PNG文件中位置为第一块chunk.

    PLTE: 调色板(palette table), 位于IDAT块以前.

    IDAT: 图像数据块, 能够有多个连续的IDAT块.

    IEND: image trailer, 在PNG文件中位置为最后一块chunk.

2.2.2 14类辅助chunk

   14类辅助chunk能够归类为如下几种:

a. Transparency information(透明信息) 

    tRNS(Transparency-透明)


b. Colour space information(颜色空间信息) 

    cHRM(Primary chromaticities and white point:基色与白色点)

    gAMA(Image gamma:图像gamma)

    iCCP(Embedded ICC profile:内嵌ICC profile)

    sBIT(Significant bits:样本有效位)

    sRGB(Standard RGB colour space:标准RGB颜色空间)


c. Textual information(文本信息)

    iTXt(International textual data: 国际化文本数据) 

    tEXt(Textual data:文本数据)

    zTXt(Compressed textual data: 压缩文本数据)


d. Miscellaneous information(其余信息)

    bKGD(Background colour:背景颜色)

    hIST(Image histogram:图像直方图)

    pHYs(Physical pixel dimensions:物理像素尺寸)

    sPLT(Suggested palette:建议调色)


e. Time information(时间信息)

    tIME(Image last-modification time: 图像最后修改时间)

2.2.3 chunk格式

   每一块chunk由3个或4个字段组成。

   Length (长度)                       4字节    指定Chunk Data字段的长度,能够为0, 不超过(2^31-1)字节  

   Chunk Type(数据块类型)      4字节    数据块类型由ASCII字母(A-Z和a-z)组成, 

                                                每一个字节的bit 5表示chunk属性, 可参见[2]中5.4 Chunk naming conventions

   Chunk Data (数据块数据)     可变长度  存储按照Chunk Type指定的数据  

   CRC (循环冗余检测)               4字节     存储用来检测是否有错误的循环冗余码


   [2]中5.6 Chunk ordering描述了每一类chunk在PNG文件中的顺序。

   

   IEND chunk中没有data字段,所以Length字段为0, IEND chunk为如下12个字节(十六进制): 

   00 00 00 00 49 45 4E 44 AE 42 60 82 

   前4个字节为00 00 00 00,Type老是IEND(49 45 4E 44),所以,CRC码也老是AE 42 60 82,每一个PNG文件最后12字节都是相同的。

3. libpng   

    [4]是libpng官方首页,从介绍中可知道它是用ANSI C (C89)编写,须要zlib 1.0.4/1.2.5及更高版本。当前最新版本是1.6.17(2015-07-16),从1.6源码 http://sourceforge.net/p/libpng/code/ci/libpng16/tree/CHANGES 可看出1.6.18正式版本正即将发布。

    在该官网首页有如下漏洞警告信息:

    libpng versions 1.6.9 through 1.6.15 (and some subset of versions up through 1.5.20) have an integer-overflow vulnerability in png_combine_row() when decoding very wide interlaced images, which can allow an attacker to overwrite an arbitrary amount of memory with arbitrary (attacker-controlled) data. This vulnerability has been assigned ID CVE-2014-9495 and is fixed in versions 1.6.16 and 1.5.21, released on 21 December 2014.

    所以推荐尽量使用最新版本的linpng。

4. 问题分析与解决

    前面简要分析了PNG文件格式中的chunk, 以及libpng后,下面就开始分析和解决前面遇到的警告问题:

    ...\res\drawable-hdpi\add_green.png: libpng warning: iCCP: Not recognizing known sRGB profile that has been edited

4.1 iCCP chunk分析

    仍是须要先分析下iCCP chunk, 其chunk type为十六进制的69 43 43 50(iCCP)。参考[2]中11.3.3.3 iCCP Embedded ICC profile, 能够看出,iCCP chunk包含的data字段为:

    Profile name       1-79 bytes (character string)

    Null separator    1 byte (null character)

    Compression method   1 byte

    Compressed profile      n bytes

    

    其中,profile name是大小写敏感的,只能包含可打印拉丁字符与空格(即范围为十进制字符 32-126 与161-255 ), 不容许在前面与后面存在空格,不容许中间有多个连续空格。压缩方法只能取值为0,0表示对zlib数据流采用deflate压缩,接下来是压缩的profile. 

   每一个PNG文件中最多只能包含一个内嵌profile, 可经过在iCCP chunk中显式指定或在sRGB chunk中隐含指定。

4.2 出问题PNG图片iCCP chunk分析

   下面是出问题add_green.png文件中包含的iCCP chunk截图:

    

    iCCP数据块各字段的含义:   

十六进制值 描    述 
00 00 0A 4F iCCP数据块的长度,00 00 0A 4F =十进制2639
69 43 43 50 数据块类型标志,69 43 43 50的ASCII值等于iCCP

                                                                   50 68

6F 74 6F 73 68 6F 70 20 49 43 43 20 70 72 6F 66

69 6C 65 00

Profile名称,长度1~79字节,

以0做为终止符的字符串, 

ASCII值等于Photoshop ICC profile

00 压缩方法,0表示使用deflate压缩
78 DA 9D 53~03 98 F3 FC 压缩的profile,解码时使用
63 33 2D DB CRC

    所以,这里的iCCP chunk的data字段从0x3D开始,因为长度为0A 4F, 所以data字段范围为0x00 3D~ 0A 8C。

       

4.3 libpng代码分析

   从 http://sourceforge.net/p/libpng/code/ci/libpng16/tree/  下载代码,可看到告警信息是在int png_compare_ICC_profile_with_sRGB( )函数中出现的:

    经过检查http://sourceforge.net/p/libpng/code/ci/d630301d996b152de09028bb6803c4c136a0e85f/log/?path=%2Fpng.c, 可看到png.c中这个函数是在2012.03.29由 John Bowler新增的,修改注释信息为:

    [libpng16] Recognize known sRGB ICC profiles while reading; prefer writing the iCCP profile over writing the sRGB chunk, controlled by the PNG_sRGB_PROFILE_CHECKS option.

    代码中利用PNG_ICC_CHECKSUM宏来定义数组png_sRGB_checks[]中的一项,每一项的结构字段包括adler crc, length, MD5[4], have_md5, is_broken, intent, 见下图:

   

    PNG_ICC_CHECKSUM宏里后三个参数date, length, file-name只是用于标记。

    // 如下4个ICC sRGB profiles是来自于 www.color.org, 每一个都有MD5校验码

    

     下面3个profiles没有明确的MD5校验码,若是匹配空的MD5则用其余字段来尝试匹配并给出警告。下面这些profiles中前两个有一个'cprt' tag, 表示它们是由HP(Hewlett Packard)建立的。

    

    根据png_compare_ICC_profile_with_sRGB( )函数中的逻辑,遍历png_sRGB_checks[]数组,当.md5[4]与profile中的md5值相同,length, intent, adler也相同,但从新计算的crc不等时,就将提示“Not recognizing known sRGB profile that has been edited”警告信息。

   scripts/pnglibconf.dfa文件中说明了本次修改的意图以及缺省检查级别为2的理由:

    setting sRGB_PROFILE_CHECKS default 2

   详细可参见[5]。

4.4 警告信息分析

    结合libpng中png.c文件 png_compare_ICC_profile_with_sRGB( )函数能够看出,当profile的许多字段都相同时,若是crc不等则提示“Not recognizing known sRGB profile that has been edited”警告信息。

   前面对出问题add_green.png文件分析可得出iCCP chunk中压缩的profile的最后四个字节是03 98 F3 FC, 对应的就是png_sRGB_checks[]数组中最后一个profile的adler字段:

    PNG_ICC_CHECKSUM(0x0398f3fc, 0xf29e526d,

      PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 1/*broken*/,

      "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 media-relative")

   所以,这张图的iCCP profile file name就是"HP-Microsoft sRGB v2 media-relative"。

 

    从https://github.com/madler/zlib/blob/master/zlib.h 中struct z_stream能够看出:

   uLong   adler;      /* adler32 value of the uncompressed data */

   字段adler就是未压缩数据的adler值。那么这个adler字段是作什么用的呢?根据[6], Adler-32校验和在zlib中做为CRC32几乎是可靠的,可是计算起来更快,将iCCP profile data压缩后就追加在data后面。adler其实就是创始人Mark Adler的名字。

4.5 回答第一章节中提出的问题

    综上,经过对PNG文件格式中iCCP chunk中profile的分析,libpng中png.c文件的分析,www.color.org中ICC sRGB profiles的说明,以及对zlib.h中adler32的分析,能够得出如下结论:

    当PNG图片中iCCP chunk中压缩的profile在处理时,当md5, length, intent, adler32等字段相同,但从新计算的crc不等时则提示“Not recognizing known sRGB profile that has been edited”警告信息。

    上述警告信息在2012.03.29由 John Bowler新增的png_compare_ICC_profile_with_sRGB( )函数在检查时给出,即libpng 1.6.0正式版本中引入这个检查函数。

4.6 问题解决

     明确了linpng严格检查的版本以及检查的内容后,那么如何来解决该问题呢。

4.6.1 解决方案1: 删除png图片内嵌的iCCP profile sRGB

    [13, 16, 17]中有一些答案建议经过Image Magick/mogrify/GIMP/exiftool等工具来"convert"或"mogrify"图片,删除png图片中内嵌的iCCP profile sRGB:

   Image Magick使用举例:

       删除单个png文件内的profile:  % convert -strip <input filename> <output filename>

       批量删除全部png文件内的profile sRGB:

           set fn=E:\Program Files\ImageMagick-6.9.0-Q16\convert.exe

           for /f "tokens=*" %%i in ('dir/s/b *.png') do "%fn%" "%%i" -strip "%%i"

   mogrify使用举例:

       删除单个png文件内的profile sRGB:  mogrify +profile sRGB <png file>

      批量删除全部png文件内的profile sRGB:

             find <path to res folder> -name *.png -exec mogrify +profile sRGB {}  \;

    GIMP使用举例:

       删除内嵌profile, 可先进入Image > Mode > Assign Color Profile并设置为RGB workspace(sRGB built-in), 而后File > Overwrite add_green.png覆盖原来的png文件。

       修改内嵌profile, 可进入Image > Mode > Convert to Color Profile, 可选择一种profile。


   [17]也还提到:libpng 1.6+更严格的检查会对original HP/MS sRGB profile报警。老的profile使用D50 whitepoint, 而D65才是标准。这种profile由Adobe Photoshop使用, 虽然缺省在png图片中并不嵌入该profile。最简单的方法是从图片中删除内嵌的profile,但这会致使颜色有稍许误差(当有颜色校订系统时)。但若是不但愿颜色有误差(例如用于打印输出), 能够嵌入另外一种不一样的颜色profile。

   [13]中也有网友指出:这样删除png图片中的iCCP profile sRGB, 将丢失如何来render图片等信息,png中的色彩可能被改变。

4.6.2 解决方案2:  将aRGB转换为sRGB

   [14]中有网友提到:这个图片是sRGB的改为ARGB(Adobe RGB)的就能够啦,在Android  Studio中的右上角会显示24位而ARGB的图片显示是32位,但我本地报这种警告的png图片除了有32位之外还有24位的,所以这个方案不太可行。

  综合上面的意见,[17]中给出的结论比较使人信服,利用GIMP工具删除内嵌的profile后问题解决。

5. 参考资料   

[1] Libpng 1.6.17 - March 26, 2015, http://www.libpng.org/pub/png/src/libpng-1.6.17-README.txt

[2] Portable Network Graphics (PNG) Specification (Second Edition), http://www.w3.org/TR/2003/PR-PNG-20030520/

[3] PNG文件结构分析, http://wenku.baidu.com/view/b87e978583d049649b66586a.html?re=view

[4] libpng官方, http://libmng.com/pub/png/libpng.html

[5] [libpng16] Recognize known sRGB ICC profiles while reading, http://sourceforge.net/p/libpng/code/ci/921648a997e733eb63e18e835a9b98a5507da197/

[6] zlib库剖析(1):实现概览, http://blog.csdn.net/zhoudaxia/article/details/8034606

[7] 图片资源添加出现问题: No resource found that matches the given name 安卓 maven编译, http://1985wanggang.blog.163.com/blog/static/77638332015011114647601/

[8] zlib Technical Details, http://www.zlib.net/zlib_tech.html

[9] 漫谈显示器色彩管理(一), http://zhuanlan.zhihu.com/hardware/19648994

[10] 漫谈显示器色彩管理(二), http://zhuanlan.zhihu.com/hardware/19649559

[11] 漫谈显示器色彩管理(三), http://zhuanlan.zhihu.com/hardware/19649897

[12] 漫谈显示器色彩管理(四), http://zhuanlan.zhihu.com/hardware/19651812

[13] Issue 77704: Built tools 21.0.1: multiple libpng warnings, https://code.google.com/p/android/issues/detail?id=77704

[14] AndroidStudio中\com.android.support错误如何解决, http://ask.csdn.net/questions/161424

[15] sRGB与aRGB的颜色设置转换, http://blog.sina.com.cn/s/blog_6cf45fc10102v81s.html

[[16] libpng warning: iCCP: Not recognizing known sRGB profile that has been edited, https://groups.google.com/forum/#!msg/adt-dev/rjTQ_STR3OE/-UcNQRISTKsJ

[17] libpng errors, https://wiki.archlinux.org/index.php/Libpng_errors

[18] GIMP, http://www.gimp.org/

相关文章
相关标签/搜索