標籤:
轉:http://my.oschina.net/1pei/blog/479162
PNG格式:每個PNG檔案是由一個PNG標識(signature),後面跟一些資料區塊(chunk),每個chunk由
一個chunk類型來標識其功能。
摘要 本文解決了Android Studio 1.2.2下編譯期間出現的libpng warning: iCCP: Not recognizing known sRGB profile that has been edited警告問題。
目錄[-]
- 1. 問題描述
- 2. PNG檔案格式
- 2.2 資料區塊(chunk)
- 2.2.1 4類關鍵chunk
- 2.2.2 14類輔助chunk
- 2.2.3 chunk格式
- 3. libpng
- 4. 問題分析與解決
- 4.1 iCCP chunk分析
- 4.2 出問題PNG圖片iCCP chunk分析
- 4.3 libpng程式碼分析
- 4.4 警告資訊分析
- 4.5 回答第一章節中提出的問題
- 4.6 問題解決
- 4.6.1 解決方案1: 刪除png圖片內嵌的iCCP profile sRGB
- 4.6.2 解決方案2: 將aRGB轉換為sRGB
- 5. 參考資料
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/
android studio問題-ICCP:Not recognizing known sRGB profile