jpeg图片格式详解

两盒软妹~` 提交于 2020-01-12 02:42:23

————————————————
版权声明:本文为CSDN博主「yun_hen」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yun_hen/article/details/78135122

peg图片格式详解
1. JPEG文件简介
JPEG的全称是JointPhotographicExpertsGroup(联合图像专家小组),它是一种常用的图像存储格式, jpg/jpeg是24位的图像文件格式,也是一种高效率的压缩格式,文件格式是JPEG(联合图像专家组)标准的产物,该标准由ISO与CCI TT(国际电报电话咨询委员会)共同制定,是面向连续色调静止图像的一种压缩标准。其最初目的是使用64Kbps的通信线路传输720×576 分辨率压缩后的图像。通过损失极少的分辨率,可以将图像所需存储量减少至原大小的10%。由于其高效的压缩效率和标准化要求,目前已广泛用于彩色传真、静止图像、电话会议、印刷及新闻图片的传送上。但那些被删除的资料无法在解压时还原,所以* .jpg/.jpeg文件并不适合放大观看,输出成印刷品时品质也会受到影响。不过,普通用户不必担心,因为.jpg/.jpeg的压缩算法十分先进,它对图形图像的损失影响不是很大,一幅1 6 M(24位)的.jpg/.jpeg图像看上去与照片没有多大差别,非专业人士甚至无法分辨。同样一幅画面,用.jpg/.jpeg格式储存的文件是其他类型图形文件的1 /10~1/20。一般情况下,.jpg/*.jpeg文件只有几十KB,而色彩数最高可达到24位,所以它被广泛运用在Internet上,以节约宝贵的网络传输资源。同样,为了在一张光盘上储存更多的图形图像,C D出版商也乐意采用jpg/jpeg格式。

JPEG的文件格式一般有两种文件扩展名:.jpg和.jpeg,这两种扩展名的实质是相同的,我们可以把.jpg的文件改名为.jpeg,而对文件本身不会有任何影响。严格来讲,JPEG的文件扩展名应该为.jpeg,由于DOS时代的8.3文件名命名原则,就使用了.jpg的扩展名,这种情况类似于.htm和.html的区别。

JPEG格式可以分为标准JPEG、渐进式JPEG和JPEG2000三种格式。

标准JPEG:该类型的图片文件,在网络上应用较多,只有图片完全被加载和读取完毕之后,才能看到图片的全貌;它是一种很灵活的图片压缩方式,用户可以在压缩比和图片品质之间进行权衡。不过,通常来讲,其压缩比在10:1到40:1之间,压缩比越大,品质就越差,压缩比越小,品质就越好。JPEG格式压缩的主要是高频信息,对色彩的信息保留较好,适合应用于互联网,可减少图像的传输时间,可以支持24bit真彩色,也普遍应用于需要连续色调的图像。JPEG由于可以提供有损压缩,因此压缩比可以达到其他传统压缩算法无法比拟的程度。其压缩模式有以下几种:顺序式编码(SequentialEncoding),递增式编码(ProgressiveEncoding),无失真编码(LosslessEncoding)和阶梯式编码(HierarchicalEncoding)。JPEG的压缩,分为四个步骤:

(1)颜色转换:由于JPEG只支持YUV颜色模式,而不支持RGB颜色模式,所以在将彩色图像进行压缩之前,必须先对颜色模式进据转换。转换完成之后还需要进行数据采样。一般采用的采样比例是2:1:1或4:2:2。由于在执行了此项工作之后,每两行数据只保留一行,因此,采样后图像数据量将压缩为原来的一半。

(2)DCT变换:DCT(DiscreteConsineTransform)是将图像信号在频率域上进行变换,分离出高频和低频信息的处理过程。然后再对图像的高频部分(即图像细节)进行压缩,以达到压缩图像数据的目的。首先将图像划分为多个8*8的矩阵。然后对每一个矩阵作DCT变换(变换公式此略)。变换后得到一个频率系数矩阵,其中的频率系数都是浮点数。

(3)量化:由于在后面编码过程中使用的码本都是整数,因此需要对变换后的频率系数进行量化,将之转换为整数。由于进行数据量化后,矩阵中的数据都是近似值,和原始图像数据之间有了差异,这一差异是造成图像压缩后失真的主要原因。

(4)编码:编码采用两种机制:一是0值的行程长度编码;二是熵编码(EntropyCoding)。在JPEG中,采用曲徊序列,即以矩阵对角线的法线方向作“之”字排列矩阵中的元素。这样做的优点是使得靠近矩阵左上角、值比较大的元素排列在行程的前面,而行程的后面所排列的矩阵元素基本上为0值。行程长度编码是非常简单和常用的编码方式,在此不再赘述。编码实际上是一种基于统计特性的编码方法。在JPEG中允许采用HUFFMAN编码或者算术编码。

渐进式JPEG:该类型的图片是对标准JPEG格式的改进,当在网页上下载渐进式JPEG图片时,首先呈现图片的大概外貌,然后再逐渐呈现具体的细节部分,因而被称之为渐进式JPEG。

JPEG2002:一种全新的图片压缩发,压缩品质更好,并且改善了无线传输时,因信号不稳定而造成的马赛克及位置错乱等问题。另外,作为JPEG的升级版,JPEG2000的压缩率比标准JPEG高约30%,同时支持有损压缩和无损压缩。它还支持渐进式传输,即,先传输图片的粗略轮廓,然后,逐步传输细节数据,使得图片由模糊到清晰逐步显示。此外,JPEG2000还支持感兴趣区域,也就是说,可以指定图片上感兴趣区域的压缩质量,还可以选择指定的部分先进行解压。

2. android是如何识别JEPG文件的
其实很简单,就是判断前面3个字节是什么,如果发现是FF D8 FF开始,那就认为它是JEPG图片。(注意android不是根据后缀名来判断是什么文件的,当然你必须是图片的后缀名文件管理器才可以打开)

//SkImageDecoder_libjpeg.cpp (external\skia\src\images)
static bool is_jpeg(SkStream* stream) {
    //需要匹配的字节
    static const unsigned char gHeader[] = { 0xFF, 0xD8, 0xFF };
    static const size_t HEADER_SIZE = sizeof(gHeader);

    char buffer[HEADER_SIZE];
    //从数据源中读取3个字节
    size_t len = stream->read(buffer, HEADER_SIZE);

    if (len != HEADER_SIZE) {
        return false;   // can't read enough
    }
    //只有完全匹配才会认为是jpeg图片
    if (memcmp(buffer, gHeader, HEADER_SIZE)) {
        return false;
    }
    return true;
}

3. JPEG图片格式详解
JPEG图片格式组成部分:SOI(文件头)+APP0(图像识别信息)+ DQT(定义量化表)+ SOF0(图像基本信息)+ DHT(定义Huffman表) + DRI(定义重新开始间隔)+ SOS(扫描行开始)+ EOI(文件尾)

其中粗体部分是必须的,下面我就来解释一下这些信息吧。

3.1 JPEG图片的数据源
先打开一张jpeg.jpeg图片,查看其图片格式与信息。 

图表 1 jpeg图片详细信息

接着以2进制形式打开该图片,查看图片的二进制原始数据=> 

图表 2 jpeg图片二进制数据

我们就以上面jpeg文件为例子,讲解我们接下去的内容。

3.2 JEPG的段结构
JPEG 文件的格式是分为一个一个的段来存储的,段的多少和长度并不是一定的。只要包含了足够的信息,该JPEG文件就能够被打开,呈现给人们。JPEG文件的每个段都一定包含两部分一个是段的标识,它由两个字节构成:第一个字节是十六进制0xFF,第二个字节对于不同的段,这个值是不同的。紧接着的两个字节存放的是这个段的长度(除了前面的两个字节0xFF和0xXX,X表示不确定。他们是不算到段的长度中的)。注意:这个长度的表示方法是按照高位在前,低位在后的,与 Intel 的表示方法不同。比方说一个段的长度是0x12AB,那么它会按照0x12,0xAB的顺序存储。但是如果按照Intel的方式:高位在后,低位在前的方式会存储成0xAB,0x12,而这样的存储方法对于JPEG是不对的。这样的话如果一个程序不认识JPEG文件某个段,它就可以读取后两个字节,得到这个段的长度,并跳过忽略它。

段的一般结构 = >

-----------------------------------------------------------------
名称  字节数     数据  说明
-----------------------------------------------------------------
段标识   1         FF      每个新段的开始标识
段类型   1                 类型编码(称作“标记码”)
段长度   2                 包括段内容和段长度本身,不包括段标识和段类型
段内容                     ≤65533字节

①JPG 文件中所有关于宽度高度长度间隔这一类数据,凡是>1字节的,均采用Motorola格式,即:高位在前,低位在后。

②有些段没有长度描述也没有内容,只有段标识和段类型。文件头和文件尾均属于这种段。

③段与段之间无论有多少FF都是合法的,这些FF称为“填充字节”,必须被忽略掉。

3.3 段类型
段类型

---------------------------------------
名称  标记码     说明
---------------------------------------
SOI     D8          文件头
EOI     D9          文件尾
SOF0    C0          帧开始(标准 JPEG)
SOF1    C1          同上
DHT     C4          定义 Huffman 表(霍夫曼表)
SOS DA          扫描行开始
DQT DB          定义量化表
DRI     DD          定义重新开始间隔
APP0    E0          定义交换格式和图像识别信息
COM FE          注释
-----------------------------------------------------------

说明:有的文章也将DNL段(标记码=DC,定义扫描行数)列为必须段。

ps:段类型有30种,但只有10种是必须被所有程序识别的,其它的类型都可以忽略。所以下面只列出这10种类型。

3.4 SOI文件头
JPEG文件的开始2个字节都是FF D8这是JPEG协议规定的

SOI(文件头)

-----------------
名称  字节数 值
-----------------
段标识   1     FF
段类型   1     D8 
-----------------

说明:这两个字节构成了JPEG文件头。

图表 3 SOI文件头

=> 此处我们的数据是FF D8

3.5 APP0图像识别信息

APP0(图像识别信息)

--------------------------------------------------------------------------
名称      字节数     值                   说明
--------------------------------------------------------------------------
段标识       1         FF
段类型       1         E0
段长度       2         0010                    如果有RGB缩略图就=16+3n
  (以下为段内容)
交换格式      5         4A46494600          “JFIF”的ASCII码
主版本号      1
次版本号      1  
密度单位      1         0=无单位;1=点数/英寸;2=点数/厘米
X像素密度     2                             水平方向的密度   
Y像素密度     2                             垂直方向的密度
缩略图X像素  1                           缩略图水平像素数目  
缩略图Y像素  1                           缩略图垂直像素数目
(如果“缩略图X像素”和“缩略图Y像素”的值均>0,那么才有下面的数据)
RGB缩略图  3×n         n=缩略图像素总数=缩略图X像素×缩略图Y像素
--------------------------------------------------------------------------

说明:

①JFIF是JPEG File Interchange Forma的缩写,即JPEG文件交换格式,另外还有TIFF等格式,很少用

②“如果有RGB缩略图就=16+3n”是什么意思呢?比如说“缩略图X像素”和“缩略图Y像素”的值均为48,就表示有一个48×48像素的缩略图(n=48×48),缩略图是24位真彩位图,用3个字节来表示一个像素,所以共占用3n个字节。但大多数JPG文件都没有这个“鸡肋”缩略图。

=>首先来看看我们图片二进制数据 

图表 4 APP0图像识别信息

1)图像识别信息头:2个字节FF E0

2)段长度:00 10 => 16个字节

3)交换格式5个字节:4A 46 49 46 00 => 此处代表‘JFIF’,一般我们用的都是JFIF的jpeg交换格式,但是也有TFIF的jpeg交换格式,如果camera sensor直接输出的是jpeg图片,那么在其sensor寄存器可以设置使用JFIF还是TFIF。

4)主版本号和次版本号一共2个字节: 01 01 => 说明主版本号和此版本号都为1

5)单位密度1个字节:01 => 表示此处使用的是点数/英寸

6)X像素密度2个字节:00 60 => 水平像素密度是96

7)Y像素密度2个字节:00 60 => 垂直像素密度是96

8)缩略图X像素:00 => 没有缩略图

9)缩略图Y像素:00 => 没有缩略图

10)RGB缩略图:此处没有缩略图,所以是空的

3.6 DQT定义量化表
DQT(定义量化表)

--------------------------------------------------------------------------
名称  字节数 值       说明
--------------------------------------------------------------------------
段标识   1     FF
段类型   1     DB
段长度   2     43      其值=3+n(当只有一个QT时)
(以下为段内容)
QT信息  1     0-3位:QT号
4-7位:QT精度(0=8bit,1字节;否则=16bit,2字节)
QT        n             n=64×QT精度的字节数
--------------------------------------------------------------------------

说明:

①JPEG文件一般有2个DQT段,为Y值(亮度)定义1个, 为C值(色度)定义1个。

②一个DQT段可以包含多个QT, 每个都有自己的信息字节

=> 接下来看看DQT的二进制数据 

图表 5 DQT定义量化表

此处有2个DQT数据,第一个是亮度的,第二个是色度的。

以第一个亮度的为例子解释:

1)定义量化表的头2个字节:FF DB

2)段长度2个字节:00 43 => 3(段长度2个字节,QT信息1个字节)+QT量化表的长度,此处QT量化表的长度是64

3)QT信息1个字节:

以①为例子00 => 0-3位是QT号,4-7位QT精度,此处是0,所以精度是8bit,即1个字节。

以②为例子 01 => QT号是1,精度是8bit

4)QT量化表:这个的长度是根据QT信息确定的,上面QT精度为8bit,所以此处是64×1 = 64个字节

3.7 SOF0图像基本信息
SOF0(图像基本信息)

--------------------------------------------------------------------------
名称  字节数 值       说明
--------------------------------------------------------------------------
段标识   1     FF
段类型   1     C0
段长度   2             其值=8+组件数量×3
  (以下为段内容)
样本精度 1      8       每个样本位数(大多数软件不支持12和16)
图片高度 2
图片宽度 2
组件数量 1      3       1=灰度图,3=YCbCr/YIQ 彩色图,4=CMYK 彩色图
  (以下每个组件占用3字节)
组件 ID     1             1=Y, 2=Cb, 3=Cr, 4=I, 5=Q
采样系数 1              0-3位:垂直采样系数
                        4-7位:水平采样系数
量化表号 1
---------------------------------------------------------------------------

说明:

①JPEG大都采用yCrCb色彩模型(y表示亮度,Cr红色分量,Cb表示蓝色分量),所以组件数量一般=3

②样本就是单个像素的颜色分量,也可理解为一个样本就是一个组件

③采样系数是实际采样方式与最高采样系数之比,而最高采样系数一般=0.5(分数表示为1/2)。比如说,垂直采样系数=2,那么2×0.5=1,表示实际采样方式是每个点采一个样,也就是逐点采样;如果垂直采样系数=1,那么:1×0.5=0.5(分数表示为1/2),表示每2个点采一个样

=> 接下来看看SOF0的二进制数据

图表 6 SOF0图像基本信息

1)图像基本信息的:2个字节FF C0

2)段长度2个字节:00 11 => 17 = 8 + 3*3,说明组件数量有3个

3)样本精度1个字节:08,每个样本的信息是8bit

4)样本高度2个字节:01 E0 => 480图片高度与实际一致

5)样本宽度2个字节:01 40 => 320图片宽度与实际一致

6)组件数量1个字节:03 => 代表YCbCr 彩色图,有3个组件分别是Y、Cb、Cr

7)每个组件占用3个字节:第一个字节是组件ID,第二个字节是采样系数,第三个字节是量化表号。

此处是:

01 22 00 => Y组件,垂直采样系数和水平采样系数都是2,量化表号是0

02 11 01 => Cb组件,垂直采样系数和水平采样系数都是1,量化表号是1

03 11 01 => Cr组件,垂直采样系数和水平采样系数都是1,量化表号是1

//此处可知此处Y采样是逐点采样,CbCr都是隔点采样,这就是标准的YUV422的数据。

3.8 DHT定义huffman表
DHT(定义Huffman表)

--------------------------------------------------------------------------
名称  字节数 值       说明
--------------------------------------------------------------------------
段标识   1     FF
段类型   1     C4
段长度   2             其值=19+n(当只有一个HT表时)
  (以下为段内容)
HT信息  1             0-3位:HT号
                                4位:   HT类型, 0=DC表,1=AC表
            5-7位:必须=0
HT位表  16            这16个数的和应该≤256
HT值表  n             n=表头16个数的和
--------------------------------------------------------------------------

说明:

①JPEG文件里有2类Haffman 表:一类用于DC(直流量),一类用于AC(交流量)。一般有4个表:亮度的DC和AC,色度的DC和AC。最多可有6个。

②一个DHT 段可以包含多个HT表, 每个都有自己的信息字节

③HT表是一个按递增次序代码长度排列的符号表。

=> 接下来看看DHT的二进制数据

图表 7 DHT定义Huffman表

1)定义Huffman表头2个字节:FF C4

2)段长度2个字节:

以①为例子 00 1F => 31 = 19(段长度2个字节+HT信息1个字节+HT位表16个字节) + 12(这个数代表HT表有12个字节)

3)HT信息1个字节:0-3位是HT号,4位是HT类型(0=DC表,1=AC表),5-7位必须为0

以①为例子 00 => HT号是0,DC表

以②为例子 10 => HT号是0,AC表

以③为例子 01 => HT号是1,DC表

以④为例子 11 => HT号是1,AC表

//此处一共有4个Haffman 表,亮度DC Haffman 表,亮度AC Haffman 表,色度DC Haffman 表,色度AC Haffman 表

4)HT位表16个字节:这16个数字值和小于等于256

以①为例子 00 01 05 01 01 01 01 01 01 00 00 00 00 00 00 00 => 共16个字节,加起来是12(此处和段长度是相匹配的),说明HT表有12个字节

5)HT值表:

以①为例子00 01 02 03 04 05 06 07 08 09 0A 0B

ps: Huffman将在后续的文档中讲解,此处不细讲。

3.9 SOS扫描行开始
SOS(扫描行开始)

--------------------------------------------------------------------------
名称          字节数 值       说明
--------------------------------------------------------------------------
段标识            1    FF
段类型            1    DA
段长度            2    000C    其值=6+2×扫描行内组件数量
  (以下为段内容)
扫描行内组件数量 1  3       必须≥1,≤4(否则错误),通常=3
  (以下每个组件占用2字节)
组件ID               1    1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q
Huffman表号      1    0-3位:AC表号 (其值=0...3)
                                    4-7位:DC表号(其值=0...3)
剩余3个字节          3           最后3个字节用途不明,忽略
--------------------------------------------------------------------------

说明:紧接SOS段后的是压缩的图像数据(一个个扫描行),数据存放顺序是从左到右、从上到下。

=> 接下来看看SOS的二进制数据

图表 8 SOS扫描行开始

1)扫描行开始的头,2个字节:FF DA

2)段长度2个字节:00 0C => 12 = 6(2个字节的扫描行开始头+1个字节扫描行内组件数量+3个字节的剩余位) + 2×3(扫描行内组件数量,每个组件2个字节)

3)扫描行内组件数量1个字节:03 => 代表组件数量数3

4)每个组件占用2个字节:

第一个字节是组件ID(1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q);第二个字节0-3位AC表号,4-7位DC表号。表号的值是0-3。

01 00 => Y组件,AC表号是0,DC表号是0

02 11 => Cb组件,AC表号是1,DC表号是1

03 11 => Cr组件,AC表号是1,DC表号是1

//此处跟DHT(定义Huffman表)的HT信息是一致的。

3.10 EOI文件尾
EOI(文件尾)

------------------
名称  字节数   值
------------------
段标识   1     FF
段类型   1     D9 
------------------

说明:这两个字节构成了JPEG文件尾。

=> EOI文件尾的二进制数据 

图表 9 EOI文件尾

=> 此处我们的数据是FF D9

3.11 其它段

1) COM(注释)

--------------------------------------------------------------------------
名称  字节数 值    说明
--------------------------------------------------------------------------
段标识   1     FF
段类型   1     FE
段长度   2     其值=注释字符的字节数+2
段内容         注释字符
--------------------------------------------------------------------------

说明:有的JPEG文件没有这个段。

2)DRI(定义重新开始间隔)

--------------------------------------------------------------------------
名称  字节数 值   说明
--------------------------------------------------------------------------
段标识   1     FF
段类型   1     DD
段长度   2     4 
  (以下为段内容)
开始间隔 2  n   复位标记的间隔距离
---------------------------------------------------------------------------

说明:

①开始间隔表示在压缩数据流中,每隔n个MCU 块就有一个RST标记,RST标记将Huffman 的解码数据流复位,DC也重新从0开始,因此,RST标记是一种复位标记

②RST 标记是一种特殊的段,它只具有段标识和段类型(长度=2字节),但它不是独立的段,只能穿插在数据流中(文件头和文件尾段也只有段标识和段类型,却都是独立的段)。

③RST标记共有8个(RST0-RST7),从RST0起开始使用,然后是RST1….直至RST7,再从RST0重复。

④RST标记的标识码是 FFD0-FFD7,对应 RST0-RST7

说明:这个不是必须段,很多JPEG都没有。

4. JPEG压缩编码实例
DC是指直流系数,是8×8个像素的平均值;AC是交流系数,是8×8个像素的其它值。压缩数据的排列方式是:亮度DC,AC,色差DC,AC,色差DC,AC。

1、每个分量如Y分量(DC+AC)完成后,如果还剩下位数,应该舍弃,后面的Cb分量是从下一个字节重新计算。

2、如果编码到后面没有压缩数据了,后面实际编码数据用0填充。

3、如果编码已经完成,那么剩余压缩数据用1填充。

4.1 8×8红色色块编码

如下图就是8×8红色色块的编码数据=> 

图表 10

8×8红色

E2        E8       A2       8A    F9       93        F7       13
11100010 11101000 10100010 10001010 11111001 10010011 11110111 00010011

计算Y亮度分量=>

--------------------------------------------------------------------------------------------------
1110-0010 11-1010-00
--------------------------------------------------------------------------------------------------

首先有一个DC系数需要计算出来

DC亮度

1110代表码长是4,类别是6,代表后面6个字节是它的值

001011是其值:最高位0代表是负数,反过来110100,代表-52

所以第一个数是:DC系数-52

AC亮度

1010:查表0/0,也就是后面都是0,代表这张图亮度都是一样的

 

 

 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!