【影象處理】Golang 獲取JPG影象的寬高
一、背景
有些業務需要判斷圖片的寬高,來做一些圖片相關縮放,旋轉等基礎操作。
但是圖片縮放,旋轉,拼接等操作需要將圖片從 JPG 格式轉成 RGBA 格式操作,操作完畢後,再轉回 JPG 圖片。
那如何不做 RGBA 的轉換就能得到 JPG 圖片的寬和高呢?
如下通過 JPG 檔案的分析,並編寫一個簡單的程式碼,從 JPG 檔案中獲取寬度和高度。
二、JPG 圖片資訊分析
分析一張 JPG 圖片時,關鍵的資訊如下,部分來自維基百科:
三、JPG開始,寬高分析
3.1 JPG格式判斷方法
JPG 圖片的開頭是0xFF 0xD8
因此,判斷 JPG 圖片的魔法檔案 magic 標識就是0xFF 0xD8
在 golang 中也是通過0xFF 0xD8判斷圖片是否為 JPG 檔案,如下所示:
&exactSig{[]byte("\xFF\xD8\xFF"), "image/jpeg"},
3.2 JPG 圖片寬高獲取
本文通過分析JPG 圖片的開始幀SOF 獲取圖片的寬高。
預覽一張圖片獲取影象的寬高基本資訊。
寬:1200,高:1002
可以使用二進位制方式開啟檔案,檢視 JPG 圖片的頭部資訊,獲取 JPG 圖片開始幀資訊如SOF0, SOF1, SOF2。
SOF0 表示baseline DCT, 基線 DCT(離散餘弦變換),開頭的標識是 0xFF 0xC0
SOF1 表示extended sequential DCT,擴充套件序列 DCT ,開頭的標識是 0xFF 0xC1
SOF2 表示progressive DCT,升級 DCT, 開頭的標識是 0xFF 0xC2
如下是一個 JPG 的頭部資訊:
從上圖中可以看到開始幀資訊是 SOF0,即 綠色標記的 ffc0。
找到 SOF 後,向後偏移5個位元組得到高和寬
高:03 ea,計算得到高等於 3<<8|0xea = 1002
寬:04 b0,計算得到寬等於4<<8|0xb0 = 1200
得到的寬高和預覽時的寬高一致。
3.3. JPG 寬高計算原理
eg: [ff c0] 00 11 08 [03 ea] [04 b0]
| | |
| | |
-> SOF1 ->height ->width
指令碼計算寬高如下:
% expr 3<<8|0xea 1002 % expr 4<<8|0xb0 1200
3.4 通過golang 實現 JPG 圖片寬高的獲取
知道了 JPG 獲取圖片寬高的原理後,使用 golang程式碼或者 JPG 圖片的寬高如下:
/** * 入參: JPG 圖片檔案的二進位制資料 * 出參:JPG 圖片的寬和高 **/ func GetWidthHeightForJpg(imgBytes []byte) (int, int) { var offset int imgByteLen := len(imgBytes) for i := 0; i < imgByteLen-1; i++ { if imgBytes[i] != 0xff { continue } if imgBytes[i+1] == 0xC0 || imgBytes[i+1] == 0xC1 || imgBytes[i+1] == 0xC2 { offset = i break } } offset += 5 if offset >= imgByteLen { return 0, 0 } height := int(imgBytes[offset])<<8 + int(imgBytes[offset+1]) width := int(imgBytes[offset+2])<<8 + int(imgBytes[offset+3]) return width, height }
總結
通過分析 JPG 圖片的 SOF 資訊,就可以提取圖片的寬和高,而不用將其轉換成 RGBA,再獲取 RGBA 的寬高,可以節約一些計算資源。
後續再分析 JPG 圖片的其他資訊,如下離散餘弦變換和哈夫曼編碼等。
Done
祝玩的開心~