java jpeg压缩解码_图片压缩(iOS)
場景很簡單,上傳圖片前壓縮圖片,節省流量和發圖時間。最近看了看 iOS 的靜態圖片壓縮,這里記個筆記。本人之前沒學過 iOS 和 Swift,本文是一篇入門文章,描述不到位之處請大家多多批評斧正。 ̄ω ̄=
從這幾個方向入手:
選擇圖片處理庫
我把它放在本文的第一位,因為接下來的代碼展示都要用到它。
我選擇的是 iOS 自帶的 Image I/O,好處是速度快、內存占用小、主流圖片格式硬解,Image and Graphics Best Practices - WWDC 2018 和 Image Resizing Techniques 中有介紹。
減小圖片尺寸
根據原圖的尺寸推測出預期縮略圖的尺寸,這個與業務場景強相關,開源的實現比如 Luban,是模仿微信的縮略圖尺寸計算邏輯。
首先獲取原圖尺寸:
let然后根據原圖尺寸區分幾種情況,這里給個 Example,真正用的話可以根據 Luban 改改:
- 短邊與長邊比例小于1/3的被算作長圖,單獨開一條分支。(比例小于 x/x 被算作超長圖)
- 正常比例的圖
- 尺寸較小的,截圖等:可視最長邊長度,尺寸等比縮小到長邊為 1280
- 尺寸較大的,照片等:可視最短邊長度,尺寸等比縮小到短邊為 1080 或 1280
計算出預期縮略圖的尺寸(thumbWidth, thumbHeight)之后,創建縮略圖 CGImage:
let快速看了下選項 kCGImageSourceSubsampleFactor 的注釋,它能令解碼后返回的圖片的長寬縮小為原圖的 1/n,n ∈ { 2, 4, 8 }。
有點像 libjpeg 支持的 IDCT Scaling,即 jpeg_decompress_struct 里的 scale_num / scale_denom。Skia(Android 用的就是它)的 SkJpegCodec 有提到,libjpeg-turbo 目前對其中的 1/4 和 1/2 有 SIMD 加速。
咳咳,跑遠了,要注意一點,用 JPEG 的 IDCT scaling 雖然快,但會導致圖像質量變差,我并沒有嘗試 kCGImageSourceSubsampleFactor 這個選項,不確定它會不會令圖像質量變差,有興趣的同學可以試試。 // TODO 之后補上
就順便一提,如果想獲得微信的縮略圖尺寸計算邏輯,可以先從日志入手,自己發幾張圖,從微信打的日志定位到具體的業務代碼。微信日志是非對稱加密的。一種方法是修改 xlog 庫,拿一臺 root 的 Android 手機,把 libwechatxlog.so pull 出來,修改成忽略公鑰,再把它 push 回去,替換掉所有 libwechatxlog.so 出現的地方,這樣就得到了一個日志不加密的微信,之后 jadx 打開,在代碼里搜索相關日志即可。另一種方法是在 Java 層加 hook,不提。
降低圖片質量
這節主要是針對 JPEG 格式寫的,JPEG 在編碼時可以選擇質量,iOS (AppleJPEG) 可以指定 0..1.0,而 libjpeg 是 0..100,不要以為它倆之間就是 1:100 的關系,實際我用工具 identify 估算了一下,iOS (AppleJPEG) 的 0.38 約對應于 libjpeg 的 60,0.44 約對應于 70。
這里我們選擇 0.38 作為質量參數:
var實際場景中,這個值可以受下發的配置和網絡狀態等環境變量影響,比如我 WIFI 下指定 0.44,4G 下指定 0.38。
改變圖片格式
- 如果想做得簡單點,編碼格式就兩種:JPEG 和 PNG。無透明色選 JPEG,有透明色選 PNG。因為 PNG 格式是無損壓縮,一般比 JPEG 格式的圖片大,也要更清晰。
透明色由 alpha channel 決定。一般 alpha channel 存在每一個像素里,當然還有其他結構的存儲方式,比如 Indexed PNG 會把它寫到獨立的 tRNS 段。判斷圖片是否包含 alpha channel 可以用 CGImage Source:
let或 CGImage 的 alphaInfo 字段:
let來判斷。這里提一下 CGImage 的 alphaInfo 字段:
public其他字段沒啥好說的,premultipliedLast 和 premultipliedFirst 代表“預乘 Alpha”,可以讓圖片的加載消耗變少,一般在游戲等 CPU (GPU) 密集的場景有用,介紹見 Premultiplied alpha。
壓縮成 JPEG 還是 PNG 也就一個參數的區別:
if另外我發現還有一個參數 kUTTypeJPEG2000,這個新的 JPEG 格式支持透明色,但推廣不起來(估計是不向前兼容的原因)。
以下手段本人還在研究,到時來填坑!!!
- 如果想做得好點復雜點,比如上傳的圖片全部編碼成 WEBP 或者更好的 HEIF(沒錯它比 WEBP 還小),那可能需要客戶端自己引入新的編碼庫,還需要服務端支持轉碼成 JPEG 或 PNG,以便用戶下載編輯。好在 HEIF 那么出名,已經有人給我們準備好庫了:libheif-rs(突然放出 Rust crate
在 iOS 11 或以上,照片格式已經是 HEIF,iOS 11 或以上也已經支持 HEIF 格式的編解碼:
if在本文的有損壓縮的場景下,HEIF 跟 JPEG 相比,雖然編碼耗時長,但輸出圖片的體積會小很多,網上有許多比較,不提。
由于 HEIF 比同等體積的 JPEG 更為清晰,質量參數可以給大點。
- 如果想把握未來,可以研究研究同事給我墻裂推薦的 AV1,這坑不填。
降低像素中每個 color component 的 depth
比如 iPhone XS Max 的截屏圖片的 color depth 都是 16-bit,降到 8-bit 圖片體積會小很多。
let多說幾句
6. PNG 有沒有有損壓縮?有,但是不適合本文的場景。TinyPNG 就是有損壓縮,開源的有 https://github.com/kornelski/pngquant,思想都是 quantization + indexed。完全可以用 pngquant 自己擼一個不輸于 TinyPNG。注意因為出來的圖是 indexed,編碼時記得 NoFilter。
7. 已經很久很久沒有寫過博客了。
總結
以上是生活随笔為你收集整理的java jpeg压缩解码_图片压缩(iOS)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: wait( )和 waitpid( )
- 下一篇: 西宁a货翡翠,孝感a货翡翠