本文始發(fā)于我的博文App圖片壓縮裁剪原理和上傳方案,以及那些有趣的事兒...,現(xiàn)轉(zhuǎn)發(fā)至此。
目錄
- App怎么壓縮質(zhì)量?
- iOS和Android壓縮接口
- 實(shí)驗(yàn)一
- 如何計(jì)算圖片的大小?
- JPEG&JFIF壓縮做了什么?
- 色彩空間轉(zhuǎn)換
- 縮減取樣
- 離散余弦變換
- 量化
- 編碼
- App怎么裁剪分辨率?
- 圖片壓縮裁剪上傳方案
- 實(shí)驗(yàn)一:上傳速度
- 實(shí)驗(yàn)二:用戶設(shè)備主要分辨率
- 實(shí)驗(yàn)三:上傳的照片的主要分辨率
- 實(shí)驗(yàn)四:壓縮質(zhì)量的大致規(guī)律
- 實(shí)驗(yàn)五:等比例裁剪后壓縮質(zhì)量的大致規(guī)律
- 實(shí)驗(yàn)六:WebP壓縮
- 制定方案
- 總結(jié)
- 附錄
- 圖像的一些概念澄清
- 壓縮算法概念
- 微信圖片處理規(guī)律
- Base64編碼后大小
- iOS的pt與Android的sp
- Android圖片質(zhì)量會(huì)比iPhone的差?
- iOS的UIImage保存圖片問題
- 壓縮再壓縮做了什么
最近有反饋說App上傳圖片偶爾會(huì)失敗,特別是在網(wǎng)速慢和iPhone 6s的機(jī)器上。有些提示是“413 Request Entity Too Large”,Request大小1.15MB。之前只是簡單地壓到0.7,沒有做裁剪等其他處理。
所以這幾天整體研究下iOS和Android的圖片壓縮裁剪和JPEG壓縮原理,也稍微找了微信發(fā)圖片的規(guī)律,越深入發(fā)現(xiàn)越多有趣的東西,問題一環(huán)扣一環(huán)。
App怎么壓縮質(zhì)量?
最先接觸的是壓縮質(zhì)量,所以看下壓縮質(zhì)量做了什么。
iOS和Android壓縮接口
iOS:
UIImageJPEGRepresentation(UIImage * __nonnull image, CGFloat compressionQuality);
// return image as JPEG. May return nil if image has no CGImageRef or invalid bitmap format. compression is 0(most)..1(least)
Android:
/**
* Write a compressed version of the bitmap to the specified outputstream.
* If this returns true, the bitmap can be reconstructed by passing a
* corresponding inputstream to BitmapFactory.decodeStream(). Note: not
* all Formats support all bitmap configs directly, so it is possible that
* the returned bitmap from BitmapFactory could be in a different bitdepth,
* and/or may have lost per-pixel alpha (e.g. JPEG only supports opaque
* pixels).
*
* @param format The format of the compressed image
* @param quality Hint to the compressor, 0-100. 0 meaning compress for
* small size, 100 meaning compress for max quality. Some
* formats, like PNG which is lossless, will ignore the
* quality setting
* @param stream The outputstream to write the compressed data.
* @return true if successfully compressed to the specified stream.
*/
compress(CompressFormat format, int quality, OutputStream stream)
從官方注釋看,iOS的compressionQuality取值從0-1,且“1”注明是least,也就是說“1”不是不壓縮,而是壓縮強(qiáng)度最弱;Android的quality取值0-100,也是100代表最大質(zhì)量,不是不壓縮。最后面測(cè)試也驗(yàn)證了這個(gè)問題,而不是網(wǎng)上很多文檔說的不壓縮。我們先統(tǒng)稱compressionQuality和quality為質(zhì)量系數(shù),下文也是。
實(shí)驗(yàn)一
于是拍了一張照片A,然后Android和iOS都?jí)嚎s得到照片B。
對(duì)比了A、B兩張圖,想看看到底影響了什么:
寬度:2448像素
高度:3264像素
分辨率:72像素/英寸
文檔:22.9MB
通道:3(RGB)
注:需弄明白附錄的關(guān)于圖像的一些概念澄清。
兩張照片看到的參數(shù)都一樣,那為什么它們的文件大小會(huì)不一樣呢?(過程中發(fā)現(xiàn)iOS的UIImage會(huì)做多一些工作,使得實(shí)驗(yàn)結(jié)果有誤,原因后面會(huì)提到。)(用Picasa看圖軟件可以查看質(zhì)量,數(shù)值上看到等于我們的質(zhì)量系數(shù))所以就想到第二個(gè)問題,文件大小怎么計(jì)算的?由什么決定?
如何計(jì)算圖片的大小?
總分辨率 * 像素表示的位數(shù)。
像素表示的位數(shù):這就涉及到色彩模式,比較常見有RGB、CMYK、YUV等。RGB一般用RGB24(還有RGB555、RGB565、RGB32),即紅綠藍(lán)都分別用8位表示,所以用了24位表示一個(gè)像素,可以組合出2^24種顏色。
上面兩張圖水平有2448個(gè)像素,垂直有3264個(gè)像素,每個(gè)像素用24b表示,按這公式大小應(yīng)該都是:2448x3264x24b=23970816B=22.86MB。為什么呢?
后來明白,原來這公式是算位圖的占用空間大小,而JPEG&JFIF是將位圖壓縮,不僅壓縮圖像質(zhì)量還壓縮圖像占用空間(后面會(huì)講到)。也就是說圖像壓縮不等于壓縮質(zhì)量和分辨率,還有壓縮占用空間。
網(wǎng)上查到JFIF文件沒有計(jì)算大小的公式,因?yàn)閴嚎s質(zhì)量和壓縮后大小沒有特定關(guān)系,如線性關(guān)系。那么JPEG&JFIF壓縮做了什么?這個(gè)質(zhì)量到底代表了什么?
JPEG&JFIF壓縮做了什么?
其實(shí)JPEG&JFIF做了兩件事情:
- 去掉視覺上的冗余信息
- 去掉數(shù)據(jù)本身結(jié)構(gòu)的冗余
第一步實(shí)現(xiàn)通過色彩空間轉(zhuǎn)換、縮減取樣、離散余弦變換、量化,第二步實(shí)現(xiàn)通過編碼。
其實(shí)這部分可以選擇跳過,只是我為了理解壓縮質(zhì)量是怎么體現(xiàn)的而去看的,后面也發(fā)現(xiàn)理解后很多問題都很清晰明白。
色彩空間轉(zhuǎn)換
JPEG需要YUV色彩模式,所以需要將RGB轉(zhuǎn)成YUV:
- Y=0.299R'+0.587G'+0.114B'
- U=-0.147R'-0.289G'+0.436B'
- V=0.615R'-0.515G'-0.100B'
縮減取樣
YUV分別代表亮度、色度、飽和度,因?yàn)槿祟惖难劬?duì)于亮度差異的敏感度高于色彩變化,所以一般會(huì)對(duì)U、V進(jìn)行縮減采樣。在JPEG上這種縮減取樣的比例可以是4:4:4(無縮減取樣)、4:2:2、4:2:0。所以經(jīng)常會(huì)看到Y(jié)UV444,YUV422和YUV420等。
離散余弦變換
將每個(gè)8x8的子區(qū)域轉(zhuǎn)換到頻率空間,這部分是無損的。
-415 -30 -61 27 56 -20 -2 0
4 -22 -61 10 13 -7 -9 5
-47 7 77 -25 -29 10 5 -6
-49 12 34 -15 -10 6 2 2
12 -7 -13 -4 -2 2 -3 3
-8 3 2 -6 -2 1 4 2
-1 0 0 -2 -1 -3 4 -1
0 0 -1 -4 -1 0 1 2
量化
量化是有損的過程,也是失真的主要原因。上面矩陣中每個(gè)值都是幅度,量化是利用人眼特點(diǎn)在高頻率上降低信息的數(shù)量(簡單地把頻率領(lǐng)域上每個(gè)成分,除以一個(gè)對(duì)于該成分的常數(shù)就可完成,且接著舍位取最接近的整數(shù)),與一個(gè)基本矩陣運(yùn)算然后得到一個(gè)新的矩陣,該新矩陣數(shù)據(jù)基本集中在左上角。
其實(shí)量化做的就是減少非0系數(shù)幅度和增加0值系數(shù)的個(gè)數(shù)。
我們接口中的質(zhì)量系數(shù)就是和這里的基本矩陣有關(guān)。
編碼
Z掃描0值行程長度編碼、哈夫曼編碼。
Z掃描0值行程長度編碼利用了量化后矩陣的特點(diǎn),使得0值的都能串在最后面,對(duì)于過早結(jié)束的最后用EOB表示。
這一步就是壓縮文件的占用空間。
App怎么裁剪分辨率?
弄清楚壓縮質(zhì)量問題后,我們知道,影響位圖的大小有分辨率,那么減少分辨率也就能使壓縮得更小了。注意這里裁剪分辨率不等于裁剪圖片,不會(huì)丟失圖片的某一部分。
iOS:
UIGraphicsBeginImageContext(newSize);
[imageFixed drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Android:
Bitmap image = BitmapFactory.decodeStream(file);
int bitmapWidth = image.getWidth();
int bitmapHeight = image.getHeight();
Matrix matrix = new Matrix();
matrix.postScale(scaleRatio, scaleRatio);
Bitmap scaledBitmap = Bitmap.createBitmap(image, 0, 0, bitmapWidth, bitmapHeight, matrix, false);
我們是等比例裁剪,比例和裁剪后占用空間大小并不一定成線性關(guān)系,這個(gè)裁剪具體怎么實(shí)現(xiàn)的和每個(gè)像素的質(zhì)量有關(guān)系。
圖片壓縮裁剪上傳方案
明白一個(gè)圖片的清晰度等受什么影響之后,可以來定下方案了,但是還得做些測(cè)試獲取數(shù)據(jù),依據(jù)數(shù)據(jù)結(jié)果來定方案。
實(shí)驗(yàn)一:上傳速度
我們用Charles模擬了各種網(wǎng)絡(luò)環(huán)境下上傳相同照片的網(wǎng)速:
| 環(huán)境 | wifi | 8M | 16M | 32M |
| :----: | :----: | :---: | :----: |
| 速度KB/s | 754.78 | 115.4 | 115.78 | 116.25 |
| 環(huán)境 | 32M光纖 | 100M光纖 | 3G | 4G |
| :----: | :----: | :---: | :----: |
| 速度KB/s | 174.65 | 167.33 | 114.18 | 174.73 |
這些不等價(jià)于我們用戶的網(wǎng)速平均值,而且只取一次樣本,所以只是作為參考。
實(shí)驗(yàn)二:用戶設(shè)備主要分辨率
因?yàn)檎掌际窃谟脩粼O(shè)備上看的,所以了解下用戶的主流分辨率,將分辨率裁剪到趨近或稍大于該主流分辨率會(huì)比較適合。iOS和Android都取接近的值。
在友盟查看了我們的應(yīng)用的相關(guān)數(shù)據(jù):
- Android,較大占比的是寬度1080像素和720像素的設(shè)備。寬度1080像素的,新增用戶占比49.69%,啟動(dòng)次數(shù)占比44.29%;寬度720像素的,新增用戶占比32.47%,啟動(dòng)次數(shù)占比37.76%。
- iOS,較大占比的是寬度1242像素、750像素和640像素的設(shè)備。寬度1242像素的,新增用戶占比31.84%,啟動(dòng)次數(shù)占比26.91%;寬度750像素的,新增用戶占比36.20%,啟動(dòng)次數(shù)占比31.59%;寬度640像素的,新增用戶占比20.36%,啟動(dòng)次數(shù)占比20.84%。
實(shí)驗(yàn)三:上傳的照片的主要分辨率
找下上傳的照片的主要分辨率,可以針對(duì)這些分辨率去確定和衡量方案。
也是在友盟上看我們的應(yīng)用的數(shù)據(jù):
- iOS主流機(jī)型是iPhone6、iPhone6s、iPhone6 Plus、iPhone6s Plus,占到70%左右。它們的拍照分辨率分別是2448x3264,3024x4032。
- Android相對(duì)較碎片化,只能是針對(duì)最大的分辨率去衡量。
實(shí)驗(yàn)四:壓縮質(zhì)量的大致規(guī)律
2448x3264照片壓縮后的數(shù)據(jù)大小(單位B):
壓縮強(qiáng)度 | 圖片1 | 圖片2 | 圖片3 | 圖片4 |
---|---|---|---|---|
0.1 | 197777 | 174464 | 152897 | 195214 |
0.2 | 212779 | 183532 | 163225 | 209426 |
0.3 | 253658 | 205512 | 196188 | 248320 |
0.4 | 360091 | 256013 | 283607 | 349968 |
0.5 | 498199 | 336823 | 390525 | 485286 |
0.6 | 724491 | 488737 | 548437 | 698421 |
0.7 | 1209508 | 883664 | 936968 | 1161342 |
0.8 | 1475669 | 1063724 | 1130241 | 1415084 |
0.9 | 1700461 | 1247600 | 1334143 | 1636293 |
1.0 | 4568157 | 3629379 | 4139209 | 4433556 |
原圖占用 | 1714688 | 1257647 | 1353635 | 1647936 |
3024x4032照片壓縮后的數(shù)據(jù)大小(單位B):
壓縮強(qiáng)度 | 圖片5 | 圖片6 | 圖片7 | 圖片8 |
---|---|---|---|---|
0.1 | 551527 | 325434 | 296792 | 492494 |
0.2 | 619307 | 352608 | 328183 | 547533 |
0.3 | 785915 | 422342 | 416459 | 683265 |
0.4 | 1061504 | 537826 | 589206 | 931686 |
0.5 | 1408297 | 891288 | 839938 | 1290788 |
0.6 | 2071014 | 973894 | 1108102 | 1607344 |
0.7 | 2547536 | 1228021 | 1756824 | 2479774 |
0.8 | 2652258 | 1320258 | 1831889 | 2617015 |
0.9 | 3336839 | 1603754 | 2212214 | 3079872 |
1.0 | 7282230 | 4337074 | 5787540 | 7962849 |
原圖占用 | 2635183 | 1511290 | 1860418 | 2641699 |
- 會(huì)出現(xiàn)壓縮出來反而比原圖大的問題,后面會(huì)討論
- 在沒有裁剪的情況下,壓到0.6依舊不是太理想,特別是分辨率更高的照片。
- 在excel表格中將數(shù)據(jù)組成折線圖,可以看出在0.9、0.8的時(shí)候下降幅度較大,后面相對(duì)平緩一點(diǎn)。
實(shí)驗(yàn)五:等比例裁剪后壓縮質(zhì)量的大致規(guī)律
2448x3264照片等比例壓縮到寬度1224像素時(shí)的數(shù)據(jù)大小(單位B):
壓縮強(qiáng)度 | 圖片1 | 圖片2 | 圖片3 | 圖片4 |
---|---|---|---|---|
0.1 | 58975 | 52025 | 43301 | 60029 |
0.2 | 64446 | 55583 | 46529 | 65347 |
0.3 | 76982 | 63805 | 55494 | 77891 |
0.4 | 99499 | 77605 | 76695 | 100042 |
0.5 | 129826 | 95116 | 103949 | 129597 |
0.6 | 173036 | 120654 | 144188 | 173569 |
0.7 | 246847 | 174977 | 209876 | 249223 |
0.8 | 303546 | 208392 | 261322 | 308841 |
0.9 | 411181 | 294795 | 358003 | 420013 |
1.0 | 1574657 | 1280563 | 1536779 | 1566585 |
原圖占用 | 1714688 | 1257647 | 1353635 | 1647936 |
3024x4032照片等比例壓縮到寬度1224像素時(shí)的數(shù)據(jù)大小(單位B):
壓縮強(qiáng)度 | 圖片5 | 圖片6 | 圖片7 | 圖片8 |
---|---|---|---|---|
0.1 | 111697 | 70802 | 54321 | 121994 |
0.2 | 127179 | 77524 | 61810 | 136869 |
0.3 | 163959 | 94048 | 79713 | 172194 |
0.4 | 225870 | 122258 | 113295 | 230197 |
0.5 | 302097 | 157160 | 155152 | 300772 |
0.6 | 395440 | 202312 | 210836 | 385183 |
0.7 | 524345 | 273895 | 295530 | 505417 |
0.8 | 623839 | 323884 | 363596 | 593923 |
0.9 | 777293 | 420943 | 481205 | 745946 |
1.0 | 2184791 | 1530139 | 1774130 | 2291622 |
原圖占用 | 2635183 | 1511290 | 1860418 | 2641699 |
- 可以看到裁剪這個(gè)分辨率后壓縮質(zhì)量0.6的大小相對(duì)可接受,而且圖片質(zhì)量影響也較小。
- 在這個(gè)分辨率下,壓縮質(zhì)量0.8時(shí)基本壓縮到1/4至1/5。
實(shí)驗(yàn)六:WebP壓縮
WebP據(jù)稱在同等質(zhì)量下大小可以壓縮至JPEG的2/3。在iOS和Android都做了WebP的壓縮測(cè)試,發(fā)現(xiàn)壓縮速度非常慢,需要20s-35s,這是很不可接受的。上網(wǎng)查到WebP的壓縮效率的確較慢,是JPEG的8倍左右,而且相比JPEG需要耗費(fèi)更多的系統(tǒng)性能。所以本來想用WebP做兜底的方案暫時(shí)落空。
制定方案
方案的目的是:
- 上傳圖片不超時(shí)
- 處理后質(zhì)量清晰度可接受
- 縮短上傳耗時(shí)
結(jié)合實(shí)驗(yàn)結(jié)論:
- 根據(jù)實(shí)驗(yàn)一,平均上傳速度100KB/s,另外我們測(cè)試很差情況下有15KB/s的情況。我們的接口超時(shí)30s,所以可接受的圖片大小最大為450KB。
- 根據(jù)實(shí)驗(yàn)二,等比例寬度取750-1242像素比較合適。
- 根據(jù)實(shí)驗(yàn)三、四、五,等比例裁剪到寬度1224像素后壓縮至0.6、0.7大小相對(duì)可接受。質(zhì)量相對(duì)可接受(主觀感受)。
- JPG、PNG和GIF圖片的基本原理及優(yōu)化方法講到,通常建議JPG質(zhì)量最好是在60左右的原因。當(dāng)在Photoshop中把質(zhì)量設(shè)置低于51的時(shí)候,它就會(huì)執(zhí)行另一個(gè)叫做“降色采樣”的優(yōu)化算法,它會(huì)在8個(gè)像素周圍平均采樣,這樣會(huì)在邊緣產(chǎn)生雜色。
定下方案:
- 照片寬度大于1224像素(因?yàn)閕Phone6照片寬度2448所以想取個(gè)可以整除的)時(shí)等比例裁剪寬度成1224。因?yàn)榉直媛侍笊踔羶杀队谑謾C(jī)分辨率實(shí)際沒有任何用處。
- 壓縮質(zhì)量系數(shù)至0.8(80)看下大小是否小于300KB,排除一些小分辨率的照片。小于則上傳,大于則繼續(xù)壓縮,取0.7(70),排除一些中等的,如果還大于則取0.6(60)后不判斷直接上傳。根據(jù)上面的實(shí)驗(yàn)可以看到在寬度1224像素下基本都會(huì)小于300KB,大于的則處于450KB內(nèi),且450KB是網(wǎng)速最差的情況,因此基本可以保證上傳。
總結(jié)
方案目前看壓縮的質(zhì)量和時(shí)間控制都相對(duì)較好,但是還要繼續(xù)觀察一段時(shí)間看需不需要再調(diào)整參數(shù)。在這過程中理清了很多概念,了解了圖片壓縮過程中發(fā)生了什么事情,挺有趣的,根本停不下來。
附錄
文中涉及到的一些概念以及發(fā)現(xiàn)的一些其他相關(guān)事情。
圖像的一些概念澄清
其實(shí)圖像真正的信息是它的總分辨率(圖像寬度x圖像高度)和分辨率(水平分辨率&垂直分辨率),而涉及到英寸、厘米等長度單位時(shí)的大小,其實(shí)不是圖像的信息,只是在涉及到外部,比如打印、設(shè)備屏幕顯示等等時(shí),換算出來的。
- 水平分辨率&垂直分辨率
分辨率一般單位ppi(也有dpi),即每英寸上多少個(gè)像素。水平分辨率即水平方向上像素個(gè)數(shù)/水平長度,垂直分辨率同理。一般水平分辨率和垂直分辨率是相等的,所以日常也簡稱為分辨率。dpi即每英寸上多少點(diǎn)。這兩個(gè)單位根據(jù)不同顯示設(shè)備有換算關(guān)系。
- 圖像寬度&圖像高度
其實(shí)標(biāo)準(zhǔn)些,講寬度&高度時(shí)一般是講圖像水平/垂直上有多少個(gè)像素。如一張2448x3264的照片,則寬度是2448像素,高度是3264像素。也有講寬度是86.36厘米,高度是115.15厘米,一般在打印照片等情況下。
- 分辨率
日常講分辨率時(shí)其實(shí)可以指很多情況,一般指圖像寬度x高度,如2448x3264,指水平上有2448個(gè)像素,垂直上有3264個(gè)像素。
壓縮算法概念
- JPEG
一個(gè)名稱為Joint Photographic Experts Group的組織,也是一種壓縮算法。JPEG本身只有描述如何將一個(gè)視頻轉(zhuǎn)換為字節(jié)的數(shù)據(jù)流(streaming),但并沒有說明這些字節(jié)如何在任何特定的存儲(chǔ)媒體上被封存起來。JPEG有有損壓縮和無損壓縮,無損壓縮的沒有得到什么支持,所以一般講JPEG指它的有損壓縮。
- JFIF
JPEG File Interchange Format,JPEG文件交換格式,詳細(xì)說明如何從一個(gè)JPEG流,產(chǎn)出一個(gè)適合于電腦存儲(chǔ)和傳輸?shù)奈募?/strong>。一般后綴有.jpeg、.jpg、.jfif以及.jif。
- Bitmap
又稱柵格圖,是使用像素陣列來表示的圖像。非壓縮格式,從左往右從上往下掃描,占用較大存儲(chǔ)空間。
https://zh.wikipedia.org/wiki/JPEG
https://zh.wikipedia.org/wiki/%E4%BD%8D%E5%9B%BE
微信圖片處理規(guī)律
經(jīng)過簡單測(cè)試發(fā)現(xiàn),在微信,A發(fā)一張?jiān)瓐D給B時(shí),B直接保存縮略圖:
- iOS版的微信保存下來是等比例壓縮高度為800,質(zhì)量80。
- Android版的微信保存下來是等比例壓縮高度為1280,質(zhì)量80。
朋友圈的圖片保存下來,都是等比例到高1280像素,質(zhì)量和大小還沒找到規(guī)律。
為什么微信是取高固定而不是寬呢?可以思考下。
Base64編碼后大小
我們現(xiàn)在還用著Base64編碼圖像數(shù)據(jù),后面需改成提交表單方式。
Base64要求把每三個(gè)8Bit的字節(jié)轉(zhuǎn)換為四個(gè)6Bit的字節(jié)(38 = 46 = 24),然后把6Bit再添兩位高位0,組成四個(gè)8Bit的字節(jié),也就是說,轉(zhuǎn)換后的字符串理論上將要比原來的長1/3。
iOS的pt與Android的sp
我在iOS所有設(shè)備的分辨率、尺寸和縮放因子,放大模式區(qū)別和6P實(shí)際分辨率文章里講了iOS設(shè)備的pt和px關(guān)系。
iOS的pt是開發(fā)單位,一個(gè)邏輯point對(duì)應(yīng)一個(gè)點(diǎn)dot。@1x設(shè)備上一個(gè)pt上顯示1個(gè)px(像素),@2x上一個(gè)pt顯示2個(gè)px,@3x上顯示3個(gè)px。平時(shí)在storyboard上設(shè)置時(shí)指的都是pt。
Android的sp一種基于屏幕密度的抽象單位。
Android圖片質(zhì)量會(huì)比iPhone的差?
在為什么Android的圖片質(zhì)量會(huì)比iPhone的差?、[Android算法] 【04/28 bug修改】android圖片壓縮終極解決方案、Android圖片編碼機(jī)制深度解析(Bitmap,Skia,libJpeg)三篇文章中講了Android系統(tǒng)在壓縮上的一些不為人知的問題。
大致是,Android編碼保存圖片就是通過Java層函數(shù)——Native層函數(shù)——Skia庫函數(shù)——對(duì)應(yīng)第三方庫函數(shù)(例如libjpeg),這一層層調(diào)用做到的。 libjpeg在壓縮圖像時(shí),有一個(gè)參數(shù)叫optimize_coding,如果設(shè)置optimize_coding為TRUE,將會(huì)使得壓縮圖像過程中基于圖像數(shù)據(jù)計(jì)算哈弗曼表,由于這個(gè)計(jì)算會(huì)顯著消耗空間和時(shí)間,默認(rèn)值被設(shè)置為FALSE。對(duì)于當(dāng)時(shí)的計(jì)算設(shè)備來說,空間和時(shí)間的消耗可能是顯著的,但到今天,這似乎不應(yīng)再是問題。但谷歌的Skia項(xiàng)目工程師們對(duì)optimize_coding在Skia中默認(rèn)的等于了FALSE,這就意味著更差的圖片質(zhì)量和更大的圖片文件。還有其他和iOS的比較可以看下。
也講到了Android可以替換libjpeg庫達(dá)到設(shè)置為TRUE的目的。
iOS的UIImage保存圖片問題
起初發(fā)現(xiàn)壓縮后保存圖片,不同壓縮質(zhì)量系數(shù),得出來的文件大小趨勢(shì)和計(jì)算出的大小趨勢(shì)不同,所以懷疑使用NSData初始化UIImage時(shí)多做了什么。
NSData *imageData06 = UIImageJPEGRepresentation(scaledImage, 0.6);
UIImage *image06 = [UIImage imageWithData:imageData06];
UIImageWriteToSavedPhotosAlbum(image06, nil, nil, nil);
通過軟件發(fā)現(xiàn),不同壓縮質(zhì)量系數(shù),得出來的NSData保存成UIImage圖片,看到的質(zhì)量都是92,按道理應(yīng)該是對(duì)應(yīng)的質(zhì)量系數(shù)才對(duì)。于是想將NSData保存成文件到目錄,讀取出文件大小。
NSString *documents = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [documents stringByAppendingPathComponent:@"image.jpg"];
NSData *imageData = UIImageJPEGRepresentation(image, 0.7);
NSError *error = nil;
[imageData writeToFile:filePath options:NSDataWritingAtomic error:&error];
if (error != nil) {
NSLog(@"error = %@", error);
}else {
NSLog(@"success");
}
NSLog(@"imageData = %u", (unsigned)imageData.length);
NSFileManager* manager = [NSFileManager defaultManager];
if ([manager fileExistsAtPath:filePath]){
unsigned long long size = [[manager attributesOfItemAtPath:filePath error:nil] fileSize];
NSLog(@"0.7后文件大小 %llu", size);
}
UIImage *imageFromData = [UIImage imageWithData:imageData];
UIImageWriteToSavedPhotosAlbum(imageFromData, nil, nil, nil);
UIImage *imageRead = [[UIImage alloc] initWithContentsOfFile:filePath];
UIImageWriteToSavedPhotosAlbum(imageRead, nil, nil, nil);
讀取文件大小size和NSData大小imageData.length打印一致,而與imageRead、imageFromData的大小不一樣,因此可以證明UIImage這個(gè)對(duì)象本身還做了其他事情。
在AFNetworking2.0源碼解析這篇文章的截圖顯示,UIImage的imageWithData方法堆棧顯示還調(diào)用了哈夫曼解碼。
壓縮再壓縮做了什么
- 首先談下看圖軟件怎么展示圖片。打開.jpg圖片時(shí),看圖軟件將文件轉(zhuǎn)換成位圖才顯示出來,即把量化表矩陣與基本轉(zhuǎn)化矩陣運(yùn)算得出圖片當(dāng)前的位圖(因?yàn)榻?jīng)過了壓縮,所以該位圖與原位圖不同)。
- 壓縮后再壓縮也是,先將圖片變回位圖,再將位圖按現(xiàn)在的壓縮質(zhì)量系數(shù)壓縮。
- 所以壓縮后的圖片有可能變大,我猜測(cè)原因是,壓縮前的占用空間壓縮率較大,而再壓縮時(shí)選的質(zhì)量系數(shù)較大,導(dǎo)致壓縮占用空間率(即壓縮的第二步)較小,所以導(dǎo)致質(zhì)量其實(shí)是變差了,但是占用空間反而可能變大。
變大的例子如:本來圖片A大小500KB,壓縮質(zhì)量系數(shù)選擇0.7,得到B圖片90KB,再拿這張B圖片去壓,壓縮質(zhì)量系數(shù)1.0,得出C圖片。前面我們說壓縮不僅壓縮質(zhì)量,還壓縮占用空間。如果第一次壓縮的壓縮質(zhì)量比例跟第二次壓縮的比例的差值,比第一次壓縮的壓縮占用空間比例跟第二次的壓縮占用空間比例的差值小,那么C圖片就會(huì)比B圖片大。因?yàn)殡m然C圖片質(zhì)量比B圖片質(zhì)量差點(diǎn),但是B圖片的空間壓縮得比C圖片大比較多。
-END-
歡迎到我的博客交流:http://zackzheng.info