設(shè)備: iPhone 7/7p +
手機系統(tǒng): iOS 11 +
在做圖片上傳的時候, 遇到一個問題: 在iPhone 7/7p以上設(shè)備拍攝的圖片, 后臺解析不了, 一直報500的內(nèi)部錯誤(Internal Server Error). 前臺查看獲取的圖片數(shù)據(jù)看似都正常, 就是將獲取到的Data數(shù)據(jù)傳到后臺后, 解析不了圖片.
獲取圖片數(shù)據(jù)的方式是使用下面這個方法:
PHImageManager.default().requestImageData(for: ass, options: option) { (data, string, orientation, info) in
}
如果是使用下面的方法直接獲取的UIIMage對象, 則不會出現(xiàn)這個問題:
PHCachingImageManager.default().requestImage(for: ass, targetSize: PHImageManagerMaximumSize, contentMode: .default, options: option) { (image, info) in
}
但是數(shù)據(jù)量會比直接獲取data小一些, 因為我這個圖片是作為印刷的, 所以為了保證圖片質(zhì)量, 直接獲取了原始data, 其實也沒差多少.
一開始以為是新設(shè)備或者系統(tǒng)的原因, 接著發(fā)現(xiàn)使用統(tǒng)一設(shè)備, APP內(nèi)自定義的相機拍攝的照片可以正常上傳/解析, 使用設(shè)備系統(tǒng)相機拍攝的照片, 就上傳/解析不了. 找了很多資料, 都沒有說明這個問題的, 嘗試了一些方法, 也都沒有解決. 就在感覺解決無望的時候, 打印了下獲取到的圖片信息.
這時, 才發(fā)現(xiàn)這些設(shè)備上拍攝的圖片格式是: HEIC 格式. 這是個什么鬼? 沒遇到過這種格式, 繼續(xù)查資料:
HEIC圖片格式簡介
原來HEIC是蘋果在iOS 11系統(tǒng)中采用的新的默認(rèn)圖片格式(之前默認(rèn)圖片格式都是JPG), HEIC格式文件好處在于不損失畫質(zhì)的情況下膀藐,能夠大大的減少文件所占用的空間,可以實現(xiàn)比JPG格式文件更小的空間护糖。不過也并非是所有的iOS設(shè)備都會默認(rèn)采用HEIC圖像格式,只有A9芯片及以上的設(shè)備才會使用锰扶,比如搭載最新的A11仿生的芯片的iPhone X寝受、iPhone8嗦哆、iPhone8 Plus會全部使用HEIC圖像格式,也只有這些設(shè)備和MAC才能打開HEIC格式文件, 另外在7/7p上也支持HEIC格式的圖片。
HEIC這個格式雖好棵癣,但是它屬于新生事物,各個軟件對它的支持還不完善捐迫。結(jié)果就是在Windows中爱葵,內(nèi)置圖片瀏覽器無法打開反浓,熱門的圖片查看器也還沒有對其進行格式支持的則無法打開赞哗。對于使用Mac系列電腦的用戶來說,則不會出現(xiàn)這個問題.
但是這個默認(rèn)圖片格式可以在手機設(shè)置中修改, 即: 設(shè)置-> 相機 中有個格式選項:
點進去即可選擇要保存的圖片格式:
默認(rèn)是選擇高效, 即HEIC格式, 可以修改為兼容性最好, 即JPG格式.
解決方式
查了一些資料, 基本沒有找到有效的方法能夠直接處理這種圖片格式, 后臺也無法正確解析. 一開始想要轉(zhuǎn)換成為JPG或者PNG格式, 再去處理, 沒有找到直接轉(zhuǎn)換的方法, 嘗試去間接轉(zhuǎn)換, 最后也能達(dá)到傳輸?shù)哪康?
處理這種圖片, 目前我嘗試成功的有兩種方式:
第一種方式, 就是使用上面的第二個方法, 直接獲取其UIImage對象, 然后再轉(zhuǎn)換為Data數(shù)據(jù)進行傳輸:
PHCachingImageManager.default().requestImage(for: ass, targetSize: PHImageManagerMaximumSize, contentMode: .default, options: option) { (image, info) in
if let img = image {
var data = UIImagePNGRepresentation(img)
suffix = ".png"
if data == nil {
suffix = ".jpg"
data = UIImageJPEGRepresentation(img, 1.0)
}
// 處理邏輯 ...
}
}
第二種方式, 就是使用上面第一個方法獲取到原始Data數(shù)據(jù), 然后保存到本地, 然后再讀取出來, 這里我保存到本地是圖片, 讀取出來為UIImage對象, 然后再轉(zhuǎn)換為Data數(shù)據(jù):
PHImageManager.default().requestImageData(for: ass, options: option) { (data, string, orientation, info) in
printLog(message: data)
let name = info?["PHImageFileSandboxExtensionTokenKey"] as? String
var suffix = ".jpg"
if let str = name {
if str.hasSuffix(".jpg") || str.hasSuffix(".JPG") {
suffix = ".jpg"
} else if str.hasSuffix(".png") || str.hasSuffix(".PNG") {
suffix = ".png"
} else if str.hasSuffix(".HEIC") || str.hasSuffix(".heic") {
suffix = ".heic"
}
}
if suffix == ".heic" {
let name = CacheManager.shared.saveImageData(data!)
let image = CacheManager.shared.getImage(name: name)
if let img = image {
var data = UIImagePNGRepresentation(img)
suffix = ".png"
if data == nil {
suffix = ".jpg"
data = UIImageJPEGRepresentation(img, 1.0)
}
// 處理數(shù)據(jù)邏輯 ...
}
上面的 CacheManager 類, 是我自定義的一個緩存圖片的類, 只要寫到本地都行, 然后再取出來, 這樣就能正常傳輸了.
這兩種方式, 都能將HEIC格式圖片傳送到服務(wù)器, 服務(wù)器也能正常解析. 但這樣會失去HEIC這種圖片格式的優(yōu)勢:
從HEIC格式圖片獲取到的數(shù)據(jù)大小大概只有 0.8M(用7p拍的照片);
從上面第一種方式獲取到UIImage對象, 再轉(zhuǎn)為Data數(shù)據(jù)的大小大概有14M左右, 大了許多許多啊...;
直接獲取data, 再轉(zhuǎn)為UIImage保存本地, 再讀取轉(zhuǎn)為data的數(shù)據(jù)大小大概是 15M左右, 這個是最接近原始數(shù)據(jù)大小的;
可以看出, HEIC格式的圖片是多么的節(jié)省存儲空間, 處理過的圖片在數(shù)據(jù)量上大了很多, 增加了傳輸成本. 如果您有更好的處理HEIC格式圖片的方式, 還請不吝賜教, 這里先謝過了!