iOS開發(fā)關(guān)于“發(fā)送原圖”功能問題的記錄
本文主要記錄一個(gè)bug從發(fā)現(xiàn)、定位到延期解決的過程。文末添加了已踩過的坑
近期在做“發(fā)送原圖”功能的時(shí)候,遇到一個(gè)bug:在Android、Windows、Mac 客戶端發(fā)送原圖,iOS客戶端接收,保存原圖后,原圖物理尺寸不變,存儲(chǔ)空間變小,對(duì)應(yīng)的location等Exif信息丟失。與此同時(shí),iOS客戶端之間互發(fā)原圖沒有問題。針對(duì)這個(gè)問題,做了以下測試調(diào)研,現(xiàn)記錄下來:
一. 首先介紹一下發(fā)送一張?jiān)瓐D的流程:
- 比如 Android 端發(fā)送一張?jiān)瓐D,先上傳到 IM 的服務(wù)器,上傳成功后再發(fā)送消息體;(上傳成功后,服務(wù)器會(huì)分配三個(gè)url分別對(duì)應(yīng)縮略圖、大圖、原圖)
- 接收方接收到消息體,下載縮略圖;
- 點(diǎn)擊縮略圖,下載大圖;
- 再點(diǎn)擊“查看原圖”按鈕,下載原圖;
- 下載成功后,長按圖片,保存原圖。
二. 問題定位是在***一步,保存圖片的部分:
- 下載的圖片大小與服務(wù)器存儲(chǔ)大小是完全一致的,保存之后大小就發(fā)生了變化(目前是“jpg”格式變小,“png”格式圖片變大);
- 下載的方式分別嘗試了 AFNetwoking 下載、SDWebImage 的普通下載和高級(jí)下載方式(因?yàn)楫a(chǎn)品需求要求顯示下載原圖進(jìn)度)
- 結(jié)論下載的圖片大小與服務(wù)器存儲(chǔ)大小是完全一致的是因?yàn)樵?SDWebImage 高級(jí)下載方法的 completionBlock 中有已下載的 bit 值
- 嘗試了能找到的各種保存圖片的方式,均不行
驗(yàn)證測試:將安卓端產(chǎn)生的圖片(包括拍照“jpg”和屏幕截圖“png”)從瀏覽器下載到電腦,大小不變,將該圖片文件拖到項(xiàng)目中,執(zhí)行保存圖片的方法,大小也發(fā)生了變化。
補(bǔ)充測試:安卓端拍攝一張圖片(大小為5M),發(fā)送給 iOS 客戶端(下載大小為5M),保存(大小為3M),再將該保存的圖片發(fā)給安卓客戶端(保存后為3M),安卓客戶端再發(fā)送給iOS 客戶端(保存后大小為3M)。結(jié)論:該壓縮只會(huì)進(jìn)行一次
保存圖片后,圖片的Exif信息丟失,但是Exif信息的大小遠(yuǎn)小于文件損失的大小。圖片物理尺寸沒有發(fā)生變化
三. 競品的該功能現(xiàn)狀:
- Android、Windows、Mac發(fā)送原圖,iOS客戶端接收
- 騰訊系(QQ、WeChat)各端發(fā)送接收原圖都沒有問題
- 釘釘 的圖片變小,Exif 信息丟失
- BearyChat 發(fā)送原圖的圖片變小,Exif 信息丟失
- Slack 只支持發(fā)送圖片,沒有發(fā)送原圖功能
四. 基于現(xiàn)有情況的分析
- iOS 系統(tǒng)在保存圖片的時(shí)候,會(huì)對(duì)圖片進(jìn)行編解碼操作,可能在位圖上進(jìn)行優(yōu)化
- 一張圖片的存儲(chǔ)大小的計(jì)算方式:水平像素垂直像素1色黑白或3基色*顏色深度bit數(shù) = MB數(shù),可能是不同系統(tǒng)的基數(shù)不同導(dǎo)致
- 如果要解決這個(gè)問題,要先研究一下圖片編解碼這些很底層的東西,目前來看,性價(jià)比很低
- 如果您之前踩過類似的坑并找到有效的解決方法,方便的話,勞煩請(qǐng)私信告知
五. 補(bǔ)充點(diǎn)干貨
1. 關(guān)于iOS11新增的“.heic”格式圖片
什么是“.heic”格式圖片?
之前叫“live”圖片,打開下圖紅框中的按鈕即可打開該模式,拍照后會(huì)截取拍照前后大概兩秒的一個(gè)片段,與“Gif”圖不同的是,該格式還包含了聲音(目前只有)
什么樣的手機(jī)才能拍出“.heic”格式圖片?
只有在 iOS11系統(tǒng)下且CPU為A10及其以上(***也得是iPhone 7),其他情況下拍出來的都是普通“live”圖,即在需要轉(zhuǎn)換格式的時(shí)候會(huì)自動(dòng)轉(zhuǎn)換為“.jpg/.jpeg”格式
如何判斷一張圖片是否是“.heic”格式?
SDWebImage-NSData+ImageContentType.m 已更新,剛開始遇到這個(gè)問題的時(shí)候提了個(gè)issue,還讓我提供對(duì)應(yīng)url。。
- + (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data {
- if (!data) {
- return SDImageFormatUndefined;
- }
- // File signatures table: http://www.garykessler.net/library/file_sigs.html
- uint8_t c;
- [data getBytes:&c length:1];
- switch (c) {
- case 0xFF:
- return SDImageFormatJPEG;
- case 0x89:
- return SDImageFormatPNG;
- case 0x47:
- return SDImageFormatGIF;
- case 0x49:
- case 0x4D:
- return SDImageFormatTIFF;
- case 0x52: {
- if (data.length >= 12) {
- //RIFF....WEBP
- NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
- if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {
- return SDImageFormatWebP;
- }
- }
- break;
- }
- case 0x00: {
- if (data.length >= 12) {
- //....ftypheic ....ftypheix ....ftyphevc ....ftyphevx
- NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(4, 8)] encoding:NSASCIIStringEncoding];
- if ([testString isEqualToString:@"ftypheic"]
- || [testString isEqualToString:@"ftypheix"]
- || [testString isEqualToString:@"ftyphevc"]
- || [testString isEqualToString:@"ftyphevx"]) {
- return SDImageFormatHEIC;
- }
- }
- break;
- }
- }
- return SDImageFormatUndefined;
- }
- + (nonnull CFStringRef)sd_UTTypeFromSDImageFormat:(SDImageFormat)format {
- CFStringRef UTType;
- switch (format) {
- case SDImageFormatJPEG:
- UTType = kUTTypeJPEG;
- break;
- case SDImageFormatPNG:
- UTType = kUTTypePNG;
- break;
- case SDImageFormatGIF:
- UTType = kUTTypeGIF;
- break;
- case SDImageFormatTIFF:
- UTType = kUTTypeTIFF;
- break;
- case SDImageFormatWebP:
- UTType = kSDUTTypeWebP;
- break;
- case SDImageFormatHEIC:
- UTType = kSDUTTypeHEIC;
- break;
- default:
- // default is kUTTypePNG
- UTType = kUTTypePNG;
- break;
- }
- return UTType;
- }
對(duì)于“.heic”格式圖片我們應(yīng)該怎么處理?
- 首先肯定不是服務(wù)器去支持這個(gè)類型,因?yàn)?Windows、Android 是不支持該類型的圖片正常顯示的,尤其是 Windows 明確表示以后也不會(huì)支持。
- 微信目前的處理方式是轉(zhuǎn)換成了 jpg 格式,因此直接使用 UIImageJPEGRepresentation(originalImage, 0.82); 轉(zhuǎn)換為jpg即可
- 但是經(jīng)多次測試后發(fā)現(xiàn),必須設(shè)置壓縮比為0.82,轉(zhuǎn)換后的大小才盡可能的接近原圖大小