天天看點

[Image_Codec]常見圖檔格式的封裝及編解碼-Android平台(三)JPGJPG圖檔格式

文章目錄

  • JPG圖檔格式
    • 壓縮模式和步驟
    • JPG檔案結構
    • libjpeg編解碼Jpeg圖檔

JPG圖檔格式

JPG全稱Jpeg(Joint Photographic Experts Group),是一種常用的,有損壓縮圖檔格式。壓縮比例可以選擇,這樣可以在檔案大小和圖檔品質間做一個平衡。通常采用

10:1

的壓縮比例。而實際上,JPEG是

JPEG/Exif

JPEG/JFIF

等統稱,是以Jpeg一般采用

.jpg and .jpeg, though .jpe, .jfif and .jif

等檔案字尾。JPEG壓縮方案可以很好地壓縮類似的色調,但是 JPEG 壓縮方案不能很好地處理亮度的強烈差異或處理純色區域。

壓縮模式和步驟

JPEG的壓縮模式有以下幾種:

  • 順序式編碼(Sequential Encoding)

    一次将圖像由左到右、由上到下順序處理。

  • 遞增式編碼(Progressive Encoding)

    當圖像傳輸的時間較長時,可将圖像分數次處理,以從模糊到清晰的方式來傳送圖像(效果類似GIF在網絡上的傳輸)。

  • 無失真編碼(Lossless Encoding)
  • 階梯式編碼(Hierarchical Encoding)

    圖像以數種分辨率來壓縮,其目的是為了讓具有高分辨率的圖像也可以在較低分辨率的裝置上顯示。

壓縮步驟:

  • 顔色轉換

    由于JPEG隻支援YUV顔色模式的資料結構,而不支援RGB圖像資料結構,是以在将彩色圖像進行壓縮之前,必須先對顔色模式進行資料轉換。各個值的轉換可以通過下面的轉換公式計算得出:

    Y=0.299R+0.587G+0.114B

    U=-0.169R-0.3313G+0.5B

    V=0.5R-0.4187G-0.0813B

    其中,Y表示亮度,U和V表示顔色。

    轉換完成之後還需要進行資料采樣。一般采用的采樣比例是4:1:1或4:2:2。由于在執行了此項工作之後,每兩行資料隻保留一行,是以,采樣後圖像資料量将壓縮為原來的一半。

  • DCT變換

    DCT(Discrete Cosine Transform)是将圖像信号在頻率域上進行變換,分離出高頻和低頻資訊的處理過程。然後再對圖像的高頻部分(即圖像細節)進行壓縮,以達到壓縮圖像資料的目的。

    首先将圖像劃分為多個8*8的矩陣。然後對每一個矩陣作DCT變換,變換後得到一個頻率系數矩陣,其中的頻率系數都是浮點數。

  • 量化

    由于在後面編碼過程中使用的碼本都是整數,是以需要對變換後的頻率系數進行量化,将之轉換為整數。

    由于進行資料量化後,矩陣中的資料都是近似值,和原始圖像資料之間有了差異,這一差異是造成圖像壓縮後失真的主要原因。

    在這一過程中,品質因子的選取至為重要。值選得過大,可以大幅度提高壓縮比,但是圖像品質就比較差;反之,品質因子越小(最小為1),圖像重建品質越好,但是壓縮比越低。對此,ISO已經制定了一組供JPEG代碼實作者使用的标準量化值。

  • 編碼

    從前面過程我們可以看到,顔色轉換完成到編碼之前,圖像并沒有得到進一步的壓縮,DCT變換和量化可以說是為編碼階段做準備。

    編碼采用兩種機制:一是0值的行程長度編碼;二是熵編碼(Entropy Coding)。

    在JPEG中,采用曲徊序列,即以矩陣對角線的法線方向作“之”字排列矩陣中的元素。這樣做的優點是使得靠近矩陣左上角、值比較大的元素排列在行程的前面,而行程的後面所排列的矩陣元素基本上為0值。行程長度編碼是非常簡單和常用的編碼方式,在此不再贅述。

    編碼實際上是一種基于統計特性的編碼方法。在JPEG中允許采用HUFFMAN編碼或者算術編碼。

JPG檔案結構

我們将前面的Png圖檔,通過軟體轉換為Jpeg圖檔:

![JPG樣例圖檔](https://img-blog.csdn.net/20180403183607538?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NoYW9qaWFuZ2x1bw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

放大後的效果:

![放大的JPG樣例圖檔](https://img-blog.csdn.net/20180403183658438?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NoYW9qaWFuZ2x1bw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

看看轉換後的效果圖,面目全非,這就是有損壓縮的結果,圖檔已經失真~,我們這裡隻是為了說明問題用。

用二級制工具打開jpg_4_2_32bit.jpg:

00000000: ffd8 ffe0 0010 4a46 4946 0001 0101 0060  ......JFIF.....`
00000010: 0060 0000 ffdb 0043 0002 0101 0201 0102  .`.....C........
00000020: 0202 0202 0202 0203 0503 0303 0303 0604  ................
00000030: 0403 0507 0607 0707 0607 0708 090b 0908  ................
00000040: 080a 0807 070a 0d0a 0a0b 0c0c 0c0c 0709  ................
00000050: 0e0f 0d0c 0e0b 0c0c 0cff db00 4301 0202  ............C...
00000060: 0203 0303 0603 0306 0c08 0708 0c0c 0c0c  ................
00000070: 0c0c 0c0c 0c0c 0c0c 0c0c 0c0c 0c0c 0c0c  ................
00000080: 0c0c 0c0c 0c0c 0c0c 0c0c 0c0c 0c0c 0c0c  ................
00000090: 0c0c 0c0c 0c0c 0c0c 0c0c 0c0c 0c0c ffc0  ................
000000a0: 0011 0800 0200 0403 0122 0002 1101 0311  ........."......
000000b0: 01ff c400 1f00 0001 0501 0101 0101 0100  ................
000000c0: 0000 0000 0000 0001 0203 0405 0607 0809  ................
000000d0: 0a0b ffc4 00b5 1000 0201 0303 0204 0305  ................
000000e0: 0504 0400 0001 7d01 0203 0004 1105 1221  ......}........!
000000f0: 3141 0613 5161 0722 7114 3281 91a1 0823  1A..Qa."q.2....#
00000100: 42b1 c115 52d1 f024 3362 7282 090a 1617  B...R..$3br.....
00000110: 1819 1a25 2627 2829 2a34 3536 3738 393a  ...%&'()*456789:
00000120: 4344 4546 4748 494a 5354 5556 5758 595a  CDEFGHIJSTUVWXYZ
00000130: 6364 6566 6768 696a 7374 7576 7778 797a  cdefghijstuvwxyz
00000140: 8384 8586 8788 898a 9293 9495 9697 9899  ................
00000150: 9aa2 a3a4 a5a6 a7a8 a9aa b2b3 b4b5 b6b7  ................
00000160: b8b9 bac2 c3c4 c5c6 c7c8 c9ca d2d3 d4d5  ................
00000170: d6d7 d8d9 dae1 e2e3 e4e5 e6e7 e8e9 eaf1  ................
00000180: f2f3 f4f5 f6f7 f8f9 faff c400 1f01 0003  ................
00000190: 0101 0101 0101 0101 0100 0000 0000 0001  ................
000001a0: 0203 0405 0607 0809 0a0b ffc4 00b5 1100  ................
000001b0: 0201 0204 0403 0407 0504 0400 0102 7700  ..............w.
000001c0: 0102 0311 0405 2131 0612 4151 0761 7113  ......!1..AQ.aq.
000001d0: 2232 8108 1442 91a1 b1c1 0923 3352 f015  "2...B.....#3R..
000001e0: 6272 d10a 1624 34e1 25f1 1718 191a 2627  br...$4.%.....&'
000001f0: 2829 2a35 3637 3839 3a43 4445 4647 4849  ()*56789:CDEFGHI
00000200: 4a53 5455 5657 5859 5a63 6465 6667 6869  JSTUVWXYZcdefghi
00000210: 6a73 7475 7677 7879 7a82 8384 8586 8788  jstuvwxyz.......
00000220: 898a 9293 9495 9697 9899 9aa2 a3a4 a5a6  ................
00000230: a7a8 a9aa b2b3 b4b5 b6b7 b8b9 bac2 c3c4  ................
00000240: c5c6 c7c8 c9ca d2d3 d4d5 d6d7 d8d9 dae2  ................
00000250: e3e4 e5e6 e7e8 e9ea f2f3 f4f5 f6f7 f8f9  ................
00000260: faff da00 0c03 0100 0211 0311 003f 00f9  .............?..
00000270: 1ffe 0afd e28d 4ff6 66ff 0082 887c 4af0  ......O.f....|J.
00000280: 9fc3 7d46 fbe1 f785 6c75 3716 fa37 86a7  ..}F....lu7..7..
00000290: 7d27 4fb7 da4c 6bb2 0b72 91ae 1234 4185  }'O..Lk..r...4A.
000002a0: e151 4740 0514 515f a064 1ff2 2ac2 7fd7  [email protected]_.d..*...
000002b0: aa5f fa6e 27f1 ff00 8a5f f254 e2fd 63ff  ._.n'...._.T..c.
000002c0: 00a4 44ff d9                             ..D..
           

轉換後的圖檔的GFIF的存儲格式。JPEG檔案大體可以分為兩個部分:

  • 标記碼

    由兩個位元組構成,其中,前一個位元組是固定值0XFF代表了一個标記碼的開始,後一個位元組不同的值代表着不同的含義。需要提醒的是,連續的多個0XFF可以了解為一個0XFF,并表示一個标記碼的開始。另外,标記碼在檔案中一般是以标記代碼的形式出現的。例如,SOI的标記代碼是0XFFD8,即,如果JPEG檔案中出現了0XFFD8,則代表此處是一個SOI标記。

  • 壓縮資料

    一個完整的兩位元組标記碼的後面,就是該标記碼對應的壓縮資料了,它記錄了關于檔案的若幹資訊。

一些典型的标記碼,及其所代表的含義如下所示:

  • SOI
00000000: ffd8 ---- ---- ---- ---- ---- ---- ----  ......JFIF.....
           
标記碼 位元組 Payload 标記碼名 描述
SOI 0xFF 0xD8 none Start Of Image 圖像開始,标記代碼為固定值0XFFD8,用2位元組表示
  • APP0
00000000: ---- ffe0 0010 4a46 4946 0001 0101 0060  ......JFIF.....`
00000010: 0060 0000 ---- ---- ---- ---- ---- ----  .`.....C........
           
标記碼 位元組 Payload 标記碼名 描述
APP0 0XFFE0 Application 0 應用程式保留标記0,标記代碼為固定值0XFFE0,用2位元組表示;該标記碼之後包含了9個具體的字段

APP0包括8個字段:

Byte 描述
ffe0 APP0 标記
0010 資料長度:2個位元組,用來表示(1)–(9)的9個字段的總長度,即不包含标記代碼但包含本字段
4a46 4946 00 标示符:5個位元組,固定值0X4A6494600,表示了字元串“JFIF0”
0101 版本号:2個位元組,一般為0X0102,表示JFIF的版本号為1.2;但也可能為其它數值,進而代表了其它版本号
01 X,Y方向的密度機關:1個位元組,隻有三個值可選,0:無機關;1:點數每英寸;2:點數每厘米
0060 X方向像素密度:2個位元組,取值範圍未知
0060 Y方向像素密度:2個位元組,取值範圍未知
00 縮略圖垂直像素數目:1個位元組,取值範圍未知
00 縮略圖垂直像素數目:1個位元組,取值範圍未知

縮略圖RGB位圖:長度可能是3的倍數,儲存了一個24位的RGB位圖;如果沒有縮略位圖(這種情況更常見),則字段(7)(8)的取值均為0

  • APPn

App0也算是AppN中特殊的一個

标記碼 位元組 Payload 标記碼名 描述
APPn 0xFF, 0xEn variable size Application n

應用程式保留标記n(n=1—15),标記代碼為2個位元組,取值為0XFFE1–0XFFFF;包含了兩個字段:

(1)資料長度,2個位元組,表示(1)(2)兩個字段的總長度;即,不包含标記代碼,但包含本字段;

(2)詳細資訊:資料長度-2個位元組,内容不定;

  • DQT
00000010: ---- ---- ffdb 0043 0002 0101 0201 0102  .`.....C........
00000020: 0202 0202 0202 0203 0503 0303 0303 0604  ................
00000030: 0403 0507 0607 0707 0607 0708 090b 0908  ................
00000040: 080a 0807 070a 0d0a 0a0b 0c0c 0c0c 0709  ................
00000050: 0e0f 0d0c 0e0b 0c0c 0cff db00 4301 0202  ............C...
00000060: 0203 0303 0603 0306 0c08 0708 0c0c 0c0c  ................
00000070: 0c0c 0c0c 0c0c 0c0c 0c0c 0c0c 0c0c 0c0c  ................
00000080: 0c0c 0c0c 0c0c 0c0c 0c0c 0c0c 0c0c 0c0c  ................
00000090: 0c0c 0c0c 0c0c 0c0c 0c0c 0c0c 0c0c ----  ................
           
标記碼 位元組 Payload 标記碼名 描述
DQT Define Quantization Table 定義量化表;标記代碼為固定值0XFFDB;包含9個具體字段

資料長度:2個位元組,表示資料長度和多個量化表字段的總長度;即,不包含标記代碼,但包含本字段;量化表:資料長度-2個位元組,其中包括以下内容: 精度及量化表ID,1個位元組,高4位表示精度,隻有兩個可選值,0:8位;1:16位;低4位表示量化表ID,取值範圍表項,64*(精度取值+1)個位元組,例如,8位精度的量化表,其表項長度為64*(0+1)=64位元組;

本标記段中,量化表可以重複出現,表示多個量化表,但最多隻能出現4次; 本段中,包含兩個ffdb。

  • SOFO
00000090: ---- ---- ---- ---- ---- ---- ---- ffc0  ................
000000a0: 0011 0800 0200 0403 0122 0002 1101 0311  ........."......
000000b0: 01ff c400 1f00 0001 0501 0101 0101 0100  ................
           
标記碼 位元組 Payload 标記碼名 描述
SOFO ffc0 variable size Start Of Frame 幀圖像開始,标記代碼為固定值0XFFC0;包含9個具體字段:
Byte 描述
0011 資料長度:2個位元組,字段的總長度;即,不包含标記代碼,但包含本字段
08 精度:1個位元組,代表每個資料樣本的位數;通常是8位
00 02 圖像高度:2個位元組,表示以像素為機關的圖像高度,如果不支援DNL就必須大于0
00 04 圖像寬度:2個位元組,表示以像素為機關的圖像寬度,如果不支援DNL就必須大于0
03 顔色分量個數:1個位元組,由于JPEG采用YCrCb顔色空間,這裡恒定為3
0122 0002 1101 0311 01

顔色分量資訊:顔色分量個數*3個位元組,這裡通常為9個位元組;并依此表示如下一些資訊:

(a)顔色分量ID: 1個位元組;

(b)水準/垂直采樣因子:1個位元組,高4位代表水準采樣因子,低4位代表垂直采樣因子;

(c)量化表:1個位元組,目前分量使用的量化表ID

本标記段中,顔色分量資訊應該重複出現3次,因為這裡有3個顔色分量;

  • DHT
000000d0: ---- ffc4 00b5 1000 0201 0303 0204 0305  ................
000000e0: 0504 0400 0001 7d01 0203 0004 1105 1221  ......}........!
000000f0: 3141 0613 5161 0722 7114 3281 91a1 0823  1A..Qa."q.2....#
00000100: 42b1 c115 52d1 f024 3362 7282 090a 1617  B...R..$3br.....
00000110: 1819 1a25 2627 2829 2a34 3536 3738 393a  ...%&'()*456789:
00000120: 4344 4546 4748 494a 5354 5556 5758 595a  CDEFGHIJSTUVWXYZ
00000130: 6364 6566 6768 696a 7374 7576 7778 797a  cdefghijstuvwxyz
00000140: 8384 8586 8788 898a 9293 9495 9697 9899  ................
00000150: 9aa2 a3a4 a5a6 a7a8 a9aa b2b3 b4b5 b6b7  ................
00000160: b8b9 bac2 c3c4 c5c6 c7c8 c9ca d2d3 d4d5  ................
00000170: d6d7 d8d9 dae1 e2e3 e4e5 e6e7 e8e9 eaf1  ................
00000180: f2f3 f4f5 f6f7 f8f9 faff c400 1f01 0003  ................
00000190: 0101 0101 0101 0101 0100 0000 0000 0001  ................
000001a0: 0203 0405 0607 0809 0a0b ffc4 00b5 1100  ................
000001b0: 0201 0204 0403 0407 0504 0400 0102 7700  ..............w.
000001c0: 0102 0311 0405 2131 0612 4151 0761 7113  ......!1..AQ.aq.
000001d0: 2232 8108 1442 91a1 b1c1 0923 3352 f015  "2...B.....#3R..
000001e0: 6272 d10a 1624 34e1 25f1 1718 191a 2627  br...$4.%.....&'
000001f0: 2829 2a35 3637 3839 3a43 4445 4647 4849  ()*56789:CDEFGHI
00000200: 4a53 5455 5657 5859 5a63 6465 6667 6869  JSTUVWXYZcdefghi
00000210: 6a73 7475 7677 7879 7a82 8384 8586 8788  jstuvwxyz.......
00000220: 898a 9293 9495 9697 9899 9aa2 a3a4 a5a6  ................
00000230: a7a8 a9aa b2b3 b4b5 b6b7 b8b9 bac2 c3c4  ................
00000240: c5c6 c7c8 c9ca d2d3 d4d5 d6d7 d8d9 dae2  ................
00000250: e3e4 e5e6 e7e8 e9ea f2f3 f4f5 f6f7 f8f9  ................
00000260: fa-- ---- ---- ---- ---- ---- ---- ----  .............?..
           
标記碼 位元組 Payload 标記碼名 描述
DHT ffc4 variable size Define Huffman Table

定義Huffman表,标記碼為0XFFC4;包含2個字段:

(1)資料長度,2個位元組,不包含标記代碼,但包含本字段;

(2)Huffman表,資料長度-2個位元組

Huffman表包括:

包括表ID和表類型,1個位元組,高4位表示表的類型,取值隻有兩個:0,DC直流;1,AC交流;低4位,Huffman表ID;需要提醒的是,DC表和AC表分開進行編碼。 包括不同位數的碼字數量,16個位元組。包括編碼内容,16個不同位數的碼字數量之和(位元組)

Huffman表可以重複出現,一般需要重複4次。

  • DRI
标記碼 位元組 Payload 标記碼名 描述
DRI 0xFF, 0xDD 4 bytes Define Restart Interval 定義差分編碼累計複位的間隔,标記碼為固定值0XFFDD

包含2個具體字段:

資料長度:2個位元組,取值為固定值0X0004,字段的總長度;即,不包含标記代碼,但包含本字段;

MCU塊的單元中重新開始間隔:2個位元組,如果取值為n,就代表每n個MCU塊就有一個RSTn标記;第一個标記是RST0,第二個是RST1,RST7之後再從RST0開始重複;如果沒有本标記段,或者間隔值為0,就表示不存在重開始間隔和标記RST;

  • SOS
00000260: --ff da00 0c03 0100 0211 0311 003f 00f9  .............?..
00000270: 1ffe 0afd e28d 4ff6 66ff 0082 887c 4af0  ......O.f....|J.
00000280: 9fc3 7d46 fbe1 f785 6c75 3716 fa37 86a7  ..}F....lu7..7..
00000290: 7d27 4fb7 da4c 6bb2 0b72 91ae 1234 4185  }'O..Lk..r...4A.
000002a0: e151 4740 0514 515f a064 1ff2 2ac2 7fd7  [email protected]_.d..*...
000002b0: aa5f fa6e 27f1 ff00 8a5f f254 e2fd 63ff  ._.n'...._.T..c.
000002c0: 00a4 44-- --                             ..D..
           
标記碼 位元組 Payload 标記碼名 描述
SOS FFDA variable Start Of Scan 掃描開始;标記碼為0XFFDA,包含2個具體字段:
Byte 描述
00 0c 資料長度, 2個位元組,表示該字段的總長度
03 顔色分量數目:1個位元組,隻有3個可選值,1:灰階圖;3:YCrCb或YIQ;4:CMYK
0100 0211 0311 顔色分量資訊:包括以下字段,顔色分量ID:1個位元組; 直流/交流系數表ID,1個位元組,高4位表示直流分量的Huffman表的ID;低4位表示交流分量的Huffman表的ID
003f 00 壓縮圖像資料:譜選擇開始:1個位元組,固定值0X00; 譜選擇結束:1個位元組,固定值0X3F;譜選擇:1個位元組,固定值0X00
  • 資料塊
00000260: ---- ---- ---- ---- ---- ---- ---- --f9  .............?..
00000270: 1ffe 0afd e28d 4ff6 66ff 0082 887c 4af0  ......O.f....|J.
00000280: 9fc3 7d46 fbe1 f785 6c75 3716 fa37 86a7  ..}F....lu7..7..
00000290: 7d27 4fb7 da4c 6bb2 0b72 91ae 1234 4185  }'O..Lk..r...4A.
000002a0: e151 4740 0514 515f a064 1ff2 2ac2 7fd7  [email protected]_.d..*...
000002b0: aa5f fa6e 27f1 ff00 8a5f f254 e2fd 63ff  ._.n'...._.T..c.
000002c0: 00a4 44-- --                             ..D..
           
  • EOI
000002c0: ---- --ff d9                             ..D..
           
标記碼 位元組 Payload 标記碼名 描述
EOI ffd9 none End Of Image 、 圖像結束;标記代碼為0XFFD9

libjpeg編解碼Jpeg圖檔

Jpeg的編解碼,可采用libjpeg-turbo,它是采用SIMD進行加速,能夠提升編解碼的性能。Android采用的是1.5.1的版本。在github上可以下到最新版本的代碼:

https://github.com/libjpeg-turbo/libjpeg-turbo.git
           

我們的樣例代碼也可以在github上進行下載下傳 :Codec-JPGCodec

在 編譯 libjpeg時,需要根據平台進行SIMD的實作編譯:

if(${ANDROID_ABI} STREQUAL "arm")
    MESSAGE(STATUS "JPEG: arm")
    set(JPEG_SOURCES
            jpeg/libjpeg-turbo/simd/jsimd_arm_neon.S
            jpeg/libjpeg-turbo/simd/jsimd_arm.c )
elseif(${ANDROID_ABI} STREQUAL "arm64")
    MESSAGE(STATUS "JPEG: arm64")
    set(JPEG_SOURCES
            jpeg/libjpeg-turbo/simd/jsimd_arm64_neon.S
            jpeg/libjpeg-turbo/simd/jsimd_arm64.c )
... ...
else()
    MESSAGE(STATUS "JPEG: else")
    set(JPEG_SOURCES
            jpeg/libjpeg-turbo/jsimd_none.c )
endif()

add_library( jpeg
             STATIC
             jpeg/libjpeg-turbo/jcapimin.c
             jpeg/libjpeg-turbo/jcapistd.c
             jpeg/libjpeg-turbo/jaricom.c
             jpeg/libjpeg-turbo/jcarith.c
             jpeg/libjpeg-turbo/jccoefct.c
             jpeg/libjpeg-turbo/jccolor.c
             jpeg/libjpeg-turbo/jcdctmgr.c
             jpeg/libjpeg-turbo/jchuff.c
             jpeg/libjpeg-turbo/jcinit.c
             jpeg/libjpeg-turbo/jcmainct.c
             jpeg/libjpeg-turbo/jcmarker.c
             jpeg/libjpeg-turbo/jcmaster.c
             jpeg/libjpeg-turbo/jcomapi.c
             jpeg/libjpeg-turbo/jcparam.c
             jpeg/libjpeg-turbo/jcphuff.c
             jpeg/libjpeg-turbo/jcprepct.c
             jpeg/libjpeg-turbo/jcsample.c
             jpeg/libjpeg-turbo/jctrans.c
             jpeg/libjpeg-turbo/jdapimin.c
             jpeg/libjpeg-turbo/jdapistd.c
             jpeg/libjpeg-turbo/jdarith.c
             jpeg/libjpeg-turbo/jdatadst.c
             jpeg/libjpeg-turbo/jdatasrc.c
             jpeg/libjpeg-turbo/jdcoefct.c
             jpeg/libjpeg-turbo/jdcolor.c
             jpeg/libjpeg-turbo/jddctmgr.c
             jpeg/libjpeg-turbo/jdhuff.c
             jpeg/libjpeg-turbo/jdinput.c
             jpeg/libjpeg-turbo/jdmainct.c
             jpeg/libjpeg-turbo/jdmarker.c
             jpeg/libjpeg-turbo/jdmaster.c
             jpeg/libjpeg-turbo/jdmerge.c
             jpeg/libjpeg-turbo/jdphuff.c
             jpeg/libjpeg-turbo/jdpostct.c
             jpeg/libjpeg-turbo/jdsample.c
             jpeg/libjpeg-turbo/jdtrans.c
             jpeg/libjpeg-turbo/jerror.c
             jpeg/libjpeg-turbo/jfdctflt.c
             jpeg/libjpeg-turbo/jfdctfst.c
             jpeg/libjpeg-turbo/jfdctint.c
             jpeg/libjpeg-turbo/jidctflt.c
             jpeg/libjpeg-turbo/jidctfst.c
             jpeg/libjpeg-turbo/jidctint.c
             jpeg/libjpeg-turbo/jidctred.c
             jpeg/libjpeg-turbo/jmemmgr.c
             jpeg/libjpeg-turbo/jmemnobs.c
             jpeg/libjpeg-turbo/jquant1.c
             jpeg/libjpeg-turbo/jquant2.c
             jpeg/libjpeg-turbo/jutils.c
             ${JPEG_SOURCES} )

target_include_directories(jpeg PRIVATE
            jpeg/libjpeg-turbo
            jpeg/libjpeg-turbo/simd )
           

我們這裡也是采用靜态庫的形式。

  • 解碼
#include <jpeglib.h>

#include "JpegTest.h"

void jpgfile_to_jpgmem(char *jpg_file,byte **jpg,int *size)
{
    FILE *fp = fopen(jpg_file,"rb");
    if(fp == NULL) return;

    fseek(fp,0,SEEK_END);
    int length = ftell(fp);
    fseek(fp,0,SEEK_SET);

    *jpg = new byte[length];
    fread(*jpg,length,1,fp);
    *size = length;

    fclose(fp);
}

void jpgmem_to_bgr(byte *jpg,int size,byte **bgr,int *b_size,int *w,int *h)
{
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;
    cinfo.err = jpeg_std_error(&jerr);

    jpeg_create_decompress(&cinfo);
    jpeg_mem_src(&cinfo,jpg,size);

    jpeg_read_header(&cinfo,TRUE);
    jpeg_start_decompress(&cinfo);

    unsigned long width = cinfo.output_width;
    unsigned long height = cinfo.output_height;
    unsigned short depth = cinfo.output_components;

    *w = width;
    *h = height;
    *b_size = width*height*depth;
    *bgr = (byte*)malloc(width*height*depth);
    memset(*bgr,0,width*height*depth);

    JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, width*depth,1);

    byte *point = (*bgr)+(height-cinfo.output_scanline-1)*(width*depth);
    while(cinfo.output_scanline<height)
    {
        jpeg_read_scanlines(&cinfo, buffer, 1);
        memcpy(point, *buffer, width*depth);
        point -= width*depth;
    }

    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);
}

void readJpegFile(char* fileName) {
    byte* jpg = static_cast<byte*> (malloc(1024));
    int size = 0;

    jpgfile_to_jpgmem(fileName, &jpg, &size);

    my_show_byte("Jpeg raw data", jpg, size);

    byte* rgb = static_cast<byte*> (malloc(1024));
    int rgb_size = 0;
    int w = 0;
    int h = 0;
    jpgmem_to_bgr(jpg, size, &rgb, &rgb_size, &w, &h);

    ALOGE("jpgmem_to_bgr rgb_size %d w %d h %d", rgb_size, w, h);

    my_show_byte("Jpeg rgb data", rgb, rgb_size);

    free(rgb);
    free(jpg);
}
           

通過jpgfile_to_jpgmem函數,将jpg檔案,轉換為對應的位元組碼。

~ E/PngCodec: png_show_byte Jpeg raw data 1418 bytes 
FFD8FFE000104A464946000101010060
00600000FFDB00430002010102010102
02020202020202030503030303030604
040305070607070706070708090B0908
080A0807070A0D0A0A0B0C0C0C0C0709
... ...
           

logcat隻能打1024個位元組~

然後再通過jpgmem_to_bgr函數,将Jpeg的原始資料,解碼為RGR的資料:

~E/PngCodec: png_show_byte Jpeg rgb data 48 bytes
 FFFFC69F9E5E4549891216560807005352121317578C90D0
           

我們可以将這個BGR的資料,寫到Bitmap檔案中,再圖檔浏覽器打開看看,和前面的 Jpeg的圖檔是一樣的。

執行個體中的代碼可以到github上下載下傳!

Codec-JPGCodec