在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]是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文件當作文本文件來處理。函數
在png規範[2]中總計定義了18種chunk,其中4類chunk是關鍵數據塊(critical chunk),每一個PNG文件都必須包含它們,其他14類爲輔助數據塊(ancillary chunks),這是可選的數據塊。
IHDR: image header, 在PNG文件中位置爲第一塊chunk.
PLTE: 調色板(palette table), 位於IDAT塊以前.
IDAT: 圖像數據塊, 能夠有多個連續的IDAT塊.
IEND: image trailer, 在PNG文件中位置爲最後一塊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: 圖像最後修改時間)
每一塊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字節都是相同的。
[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。
前面簡要分析了PNG文件格式中的chunk, 以及libpng後,下面就開始分析和解決前面遇到的警告問題:
...\res\drawable-hdpi\add_green.png: libpng warning: iCCP: Not recognizing known sRGB profile that has been edited
仍是須要先分析下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中隱含指定。
下面是出問題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。
從 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]。
結合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的名字。
綜上,經過對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正式版本中引入這個檢查函數。
明確了linpng嚴格檢查的版本以及檢查的內容後,那麼如何來解決該問題呢。
[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中的色彩可能被改變。
[14]中有網友提到:這個圖片是sRGB的改爲ARGB(Adobe RGB)的就能夠啦,在Android Studio中的右上角會顯示24位而ARGB的圖片顯示是32位,但我本地報這種警告的png圖片除了有32位之外還有24位的,所以這個方案不太可行。
綜合上面的意見,[17]中給出的結論比較使人信服,利用GIMP工具刪除內嵌的profile後問題解決。
[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/