為了節(jié)省資源,我們希望在不同分辨率的前端上可以獲取到不同尺寸的素材資源守屉。由于最近的業(yè)務(wù)中使用的所有素材都是PNG格式的圖片,并且對(duì)圖片效果要求比較嚴(yán)格,并沒(méi)有在市面上找到可以直接使用的服務(wù)入客,于是自行實(shí)現(xiàn)整個(gè)服務(wù)。
TL;DR
首先使用ImageMagick對(duì)圖片進(jìn)行縮放(假設(shè)輸出是64*64的圖片)和去模糊腿椎,再使用pngquant對(duì)縮放后的圖片進(jìn)行有損壓縮(假設(shè)原圖顏色數(shù)量為128)桌硫。
convert src.png -resize 64x64 resize.png
convert resize.png -unsharp 1.5x1+0.7+0.02 output.png
pngquant 128 -f --ext .png output.png
工具的選擇的心路歷程
圖片縮放
最早使用了號(hào)稱命令行上的Photoshop的ImageMagick來(lái)對(duì)圖片進(jìn)行縮放。當(dāng)然功能可以實(shí)現(xiàn)啃炸,只是發(fā)現(xiàn)圖片尺寸裁剪之后铆隘,文件本身的體積反而變大了。后來(lái)嘗試了各種不同的工具肮帐,包括Java的ImageIO咖驮,Python的PIL边器,以及知名圖片壓縮服務(wù)TinyPng的SDK。不同的工具不僅裁剪后文件大小不同托修,效果也有所差異忘巧。其中TinyPng表現(xiàn)最好,大部分時(shí)候圖片被縮小后文件尺寸也會(huì)隨之減小睦刃,但是也有個(gè)別圖片仍然存在同樣的問(wèn)題砚嘴。
在查閱到相關(guān)資料png 裁剪時(shí)遇到問(wèn)題,得到了較好的解釋:
原圖類型 Type: PaletteAlpha涩拙,Base type: TrueColorAlpha际长,本身就是經(jīng)過(guò)壓縮和優(yōu)化了的。
resize 時(shí)兴泥,會(huì)進(jìn)行各種差值工育,信息也會(huì)變多,類型也變成了 TrueColorAlpha搓彻。
這里涉及到了PNG文件具體格式相關(guān)資料如绸,可以參考PNG-8、24旭贬、32區(qū)別介紹和PNG的故事怔接。
圖片顏色信息減少
在確認(rèn)造成文件變大的原因是顏色信息增多之后,自然是選擇將顏色信息適當(dāng)減少稀轨。由于我們要處理的圖片是縮小后的圖片扼脐,需要的顏色應(yīng)該不會(huì)比原圖要更多,所以我們目標(biāo)是將縮小后的圖片的顏色數(shù)較少到和原圖的顏色數(shù)相同奋刽。
這里我們使用一個(gè)有損壓縮工具pngquant來(lái)壓縮圖片和減少顏色數(shù)量瓦侮。選擇他是為數(shù)不多能直接改變顏色數(shù)的壓縮工具。
經(jīng)過(guò)縮小和壓縮之后杨名,裁剪后的圖片文件已經(jīng)明顯小于原圖脏榆。相關(guān)文件的具體信息可以通過(guò)ImageMagick的identify命令來(lái)直接查看:
identify -verbose src.png
到這一步大部分需求已經(jīng)實(shí)現(xiàn),但是卻在個(gè)別邊緣分明的素材上發(fā)現(xiàn)了明顯的邊緣模糊台谍,導(dǎo)致視覺(jué)效果不佳须喂。
圖片去模糊
首先是排查原因。
起初我以為是我在壓縮的過(guò)程中趁蕊,過(guò)分減少了輸出圖片的顏色數(shù)量坞生,導(dǎo)致細(xì)節(jié)丟失。后來(lái)發(fā)現(xiàn)那些邊緣分明的圖片在resize時(shí)就已經(jīng)出現(xiàn)了模糊現(xiàn)象掷伙,那問(wèn)題自然是在ImageMagick的使用上是己。
之后在ImageMagick的官方文檔中找到了一片《Resampling Filter》,介紹了在圖片縮放時(shí)候的會(huì)遇到的各種問(wèn)題和各種參數(shù)的使用任柜。例如:
在模糊問(wèn)題上更是有另外一片文檔《Resize Unsharp》來(lái)說(shuō)明如何處理resize過(guò)程中的模糊問(wèn)題卒废。參照文檔使用下列命令可以很好地銳化圖片:
convert resize.png -unsharp 1.5x1+0.7+0.02 output.png
至此將三個(gè)步驟整合在一起沛厨,就可以達(dá)到令人滿意的png縮小效果。
相關(guān)原理
Resize
Resize的實(shí)際處理過(guò)程叫做Resampling摔认,即重采樣逆皮。簡(jiǎn)單來(lái)說(shuō),可以看作操作一個(gè)數(shù)組参袱,增加或者減少這個(gè)數(shù)組的元素电谣,并且讓處理的結(jié)果在人眼看起來(lái)不那么糟糕。其實(shí)這是一個(gè)非常復(fù)雜的問(wèn)題抹蚀,也有人專門從事這方面的研究剿牺,這里不展開(kāi)討論,還是要看《Resampling Filter》环壤,里面介紹了各種Resampling的策略晒来,也會(huì)說(shuō)明為什么圖片縮小后顏色數(shù)量會(huì)增多。
由于這個(gè)問(wèn)題的復(fù)雜性镐捧,所以沒(méi)有一套完美的方案可以解決所有場(chǎng)景下素材的resize潜索,畢竟有太多的策略和參數(shù)可以選擇,最終的方案是需要根據(jù)需求進(jìn)行取舍的。
有損壓縮
處理中關(guān)鍵的一部是使用pngquant進(jìn)行有損壓縮演痒。為什么顏色變少之后文件尺寸迅速下降橘洞?首先是因?yàn)轭伾珨?shù)量如果少于255,輸出的圖片將可以保存為PNG-8格式鄙漏,這樣就減少了像素深度。另外主要縮小圖片的原因還是PNG本身壓縮過(guò)程中的Filtering和DEFLATE算法起作用。簡(jiǎn)而言之瞎领,如果一個(gè)數(shù)組內(nèi)相似的元素越多,那么DEFLATE就可以將其壓縮得越小随夸。而Filtering步驟可以用差分編碼的編碼方式九默,即是記錄當(dāng)前數(shù)據(jù)和某個(gè)標(biāo)準(zhǔn)值的差距來(lái)存儲(chǔ)當(dāng)前數(shù)據(jù)。
比如說(shuō)有這么一個(gè)數(shù)組[99, 100, 100, 102, 103]宾毒,我們可以將其轉(zhuǎn)存為[99, 1, 0, 2, 1]驼修。轉(zhuǎn)存的規(guī)則就是以數(shù)組第1位為標(biāo)準(zhǔn)值,標(biāo)準(zhǔn)值存儲(chǔ)原始數(shù)據(jù)诈铛,后續(xù)均存儲(chǔ)以前1位數(shù)據(jù)的差值乙各。PNG一共支持5種Filtering,基本原理相似幢竹。通過(guò)類似這樣的轉(zhuǎn)換之后耳峦,DEFLATE就可以更好得壓縮數(shù)據(jù)。
END
特別鳴謝:V友icyalala
參考資料:
PNG-8焕毫、24蹲坷、32區(qū)別介紹
Resampling Filter
減少PNG文件的大小
PNG的故事