其他分享
首页 > 其他分享> > [Image_Codec]常见图片格式的封装及编解码-Android平台(三)JPG

[Image_Codec]常见图片格式的封装及编解码-Android平台(三)JPG

作者:互联网

文章目录

JPG图片格式

JPG全称Jpeg(Joint Photographic Experts Group),是一种常用的,有损压缩图片格式。压缩比例可以选择,这样可以在文件大小和图片质量间做一个平衡。通常采用10:1的压缩比例。而实际上,JPEG是JPEG/ExifJPEG/JFIF等统称,所以Jpeg一般采用.jpg and .jpeg, though .jpe, .jfif and .jif等文件后缀。JPEG压缩方案可以很好地压缩类似的色调,但是 JPEG 压缩方案不能很好地处理亮度的强烈差异或处理纯色区域。

压缩模式和步骤

JPEG的压缩模式有以下几种:

压缩步骤:

JPG文件结构

我们将前面的Png图片,通过软件转换为Jpeg图片:

![JPG样例图片](https://www.icode9.com/i/?i=20180403183607538?)

放大后的效果:

![放大的JPG样例图片](https://www.icode9.com/i/?i=20180403183658438?)

看看转换后的效果图,面目全非,这就是有损压缩的结果,图片已经失真~,我们这里只是为了说明问题用。

用二级制工具打开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  .QG@..Q_.d..*...
000002b0: aa5f fa6e 27f1 ff00 8a5f f254 e2fd 63ff  ._.n'...._.T..c.
000002c0: 00a4 44ff d9                             ..D..

转换后的图片的GFIF的存储格式。JPEG文件大体可以分为两个部分:

一些典型的标记码,及其所代表的含义如下所示:

00000000: ffd8 ---- ---- ---- ---- ---- ---- ----  ......JFIF.....
标记码 字节 Payload 标记码名 描述
SOI 0xFF 0xD8 none Start Of Image 图像开始,标记代码为固定值0XFFD8,用2字节表示
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

App0也算是AppN中特殊的一个

标记码 字节 Payload 标记码名 描述
APPn 0xFF, 0xEn variable size Application n 应用程序保留标记n(n=1—15),标记代码为2个字节,取值为0XFFE1–0XFFFF;包含了两个字段:
(1)数据长度,2个字节,表示(1)(2)两个字段的总长度;即,不包含标记代码,但包含本字段;
(2)详细信息:数据长度-2个字节,内容不定;
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。

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个颜色分量;

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次。

标记码 字节 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;

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  .QG@..Q_.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  .QG@..Q_.d..*...
000002b0: aa5f fa6e 27f1 ff00 8a5f f254 e2fd 63ff  ._.n'...._.T..c.
000002c0: 00a4 44-- --                             ..D..
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

标签:编解码,字节,..,turbo,libjpeg,图片格式,jpeg,0c0c,Image
来源: https://blog.csdn.net/chaojiangluo/article/details/79807462