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

转载地址:http://my.oschina.net/1pei/blog/479162

摘要 

本文解决了Android Studio 1.2.2下编译期间出现的libpng warning: iCCP: Not recognizing known sRGB profile that has been edited警告问题。

1. 问题描述   

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

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

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

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

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

2. PNG文件格式   

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

 

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

 

2.1 PNG标识(signature)

    每个PNG文件的前8个字节总是包含以下值:

十进制   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/

 

 

posted @ 2015-10-20 17:58  nick_leeli  阅读(633)  评论(0编辑  收藏  举报