原文地址:http://blog.csdn.net/u012611878/article/details/52215985

图片格式详解
不知道大家有没有注意过网页里,手机里,平板里的图片,事实上,图片格式多样,不同平台对不同格式的图片支持也不一样,所以需要根据不同场合,使用不同格式的图片。
一.PNG格式
便携式网络图形(Portable Network Graphics,PNG)是一种无损压缩的位图图形格式,支持索引、灰度、RGB三种颜色方案以及Alpha通道等特性。

PNG格式有8位、24位、32位三种形式,其中8位PNG支持两种不同的透明形式(索引透明和alpha透明),24位PNG不支持透明,32位PNG在24位基础上增加了8位透明通道,因此可展现256级透明程度。

PNG8和PNG24后面的数字则是代表这种PNG格式最多可以索引和存储的颜色值。”8″代表2的8次方也就是256色,而24则代表2的24次方大概有1600多万色。

格式 最高支持色彩通道 索引色编辑支持 透明支持
PNG8 256索引色 支持 支持设定特定索引色为透明色(布尔透明)
支持为索引色附加8位透明度(256阶alpha透明)
PNG24 约1600万色 不支持 不支持
PNG32 约1600万色 不支持 支持8位透明度(256阶alpha透明)

1.PNG的文件结构

对于一个PNG文件来说,其文件头总是由位固定的字节来描述的:

进制 编码
十六进制数 89 50 4E 47 0D 0A 1A 0A

其中第一个字节0x89超出了ASCII字符的范围,这是为了避免某些软件将PNG文件当做文本文件来处理。文件中剩余的部分由3个以上的PNG的数据块(Chunk)按照特定的顺序组成,因此,一个标准的PNG文件结构应该如下:

PNG文件标志 | PNG数据块 …… | PNG数据块

2.PNG数据块(Chunk)

PNG定义了两种类型的数据块,一种是称为关键数据块(critical chunk),这是标准的数据块,另一种叫做辅助数据块(ancillary chunks),这是可选的数据块。关键数据块定义了4个标准数据块,每个PNG文件都必须包含它们,PNG读写软件也都必须要支持这些数据块。虽然PNG文件规范没有要求PNG编译码器对可选数据块进行编码和译码,但规范提倡支持可选数据块。

下表就是PNG中数据块的类别,其中,关键数据块部分我们使用_前缀加以区分。

数据块符号 数据块名称 多数据块 可选否 位置限制
_IHDR 文件头数据块 第一块
cHRM 基色和白色点数据块 在PLTE和IDAT之前
gAMA 图像γ数据块 在PLTE和IDAT之前
sBIT 样本有效位数据块 在PLTE和IDAT之前
_PLTE 调色板数据块 在IDAT之前
bKGD 背景颜色数据块 在PLTE之后IDAT之前
hIST 图像直方图数据块 在PLTE之后IDAT之前
tRNS 图像透明数据块 在PLTE之后IDAT之前
oFFs (专用公共数据块) 在IDAT之前
pHYs 物理像素尺寸数据块 在IDAT之前
sCAL (专用公共数据块) 在IDAT之前
_IDAT 图像数据块 与其他IDAT连续
tIME 图像最后修改时间数据块 无限制
tEXt 文本信息数据块 无限制
zTXt 压缩文本数据块 无限制
fRAc (专用公共数据块) 无限制
gIFg (专用公共数据块) 无限制
gIFt (专用公共数据块) 无限制
gIFx (专用公共数据块) 无限制
_IEND 图像结束数据 最后一个数据块

为了简单起见,我们假设在我们使用的PNG文件中,这4个数据块按以上先后顺序进行存储,并且都只出现一次。

(1)IHDR
文件头数据块IHDR(header chunk):它包含有PNG文件中存储的图像数据的基本信息,并要作为第一个数据块出现在PNG数据流中,而且一个PNG数据流中只能有一个文件头数据块。

文件头数据块由13字节组成,它的格式如下表所示。

域的名称 字节数 说明
Width 4 bytes 图像宽度,以像素为单位
Height 4 bytes 图像宽度,以像素为单位
Bit depth 1 bytes 颜色类型::
0:灰度图像, 1,2,4,8或16
2:真彩色图像,8或16
3:索引彩色图像,1,2,4或8
4:带α通道数据的灰度图像,8或16
6:带α通道数据的真彩色图像,8或16
ColorType 1 bytes 图像深度:
索引彩色图像:1,2,4或8
灰度图像:1,2,4,8或16
真彩色图像:8或16
Compression method 1 bytes 压缩方法(LZ77派生算法)
Filter method 1 bytes 滤波器方法
Interlace method 1 bytes 隔行扫描方法:
0:非隔行扫描
1:Adam7(由Adam M. Costello开发的7遍隔行扫描方法)

(2)PLTE
对于索引图像,调色板信息是必须的,调色板的颜色索引从0开始编号,然后是1、2……,调色板的颜色数不能超过色深中规定的颜色数(如图像色深为4的时候,调色板中的颜色数不可以超过2^4=16),否则,这将导致PNG图像不合法。

真彩色图像和带α通道数据的真彩色图像也可以有调色板数据块,目的是便于非真彩色显示程序用它来量化图像数据,从而显示该图像。

PLTE数据块是定义图像的调色板信息,PLTE可以包含1~256个调色板信息,每一个调色板信息由3个字节组成:

颜色 字节 说明
Red 1byte 0 = 黑色, 255 = 红
Green 1byte 0 = 黑色, 255 = 绿
Blue 1byte 0 = 黑色, 255 = 蓝

(3)IDAT
图像数据块IDAT(image data chunk):它存储实际的数据,在数据流中可包含多个连续顺序的图像数据块。

IDAT存放着图像真正的数据信息,因此,如果能够了解IDAT的结构,我们就可以很方便的生成PNG图像。
(4)IEND
图像结束数据IEND(image trailer chunk):它用来标记PNG文件或者数据流已经结束,并且必须要放在文件的尾部。

如果我们仔细观察PNG文件,我们会发现,文件的结尾12个字符看起来总应该是这样的:
00 00 00 00 49 45 4E 44 AE 42 60 82

不难明白,由于数据块结构的定义,IEND数据块的长度总是0(00 00 00 00,除非人为加入信息),数据标识总是IEND(49 45 4E 44),因此,CRC码也总是AE 42 60 82
3.数据块结构

PNG文件中,每个数据块由4个部分组成,如下:

名称 字节数 说明
Length (长度) 4字节 指定数据块中数据域的长度,其长度不超过(231-1)字节
Chunk Type Code (数据块类型码) 4字节 数据块类型码由ASCII字母(A-Z和a-z)组成
Chunk Data (数据块数据) 可变长度 存储按照Chunk Type Code指定的数据
CRC (循环冗余检测) 4字节 存储用来检测是否有错误的循环冗余码

CRC(cyclic redundancy check)域中的值是对Chunk Type Code域和Chunk Data域中的数据进行计算得到的。CRC具体算法定义在ISO 3309和ITU-T V.42中,其值按下面的CRC码生成多项式进行计算:

x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1

二.JPEG格式

其实JPEG 和JPG没有区别,JPG的全名、正式扩展名是JPEG。但因DOS、Windows 95等早期系统采用的8.3命名规则只支持最长3字符的扩展名,为了兼容采用了.jpg。也因历史习惯和兼容性考虑,.jpg目前更流行。

总的来说:JPEG是文件格式,JPG是扩展名。

JPG即使用JPEG文件交换格式存储的编码图像文件扩展名。 JPEG联合图象专家组,是一种压缩标准。两种文件应该没有区别,如果做文件扩展名严格地说应是JPG。

JPEG是一个压缩标准,又可分为标准 JPEG、渐进式JPEG及JPEG2000三种:

①标准JPEG:以24位颜色存储单个光栅图像,是与平台无关的格式,支持最高级别的压缩,不过,这种压缩是有损耗的。此类型图片在网页下载时只能由上而下依序显示图片,直到图片资料全部下载完毕,才能看到全貌。

②渐进式 JPEG:渐进式JPG为标准JPG的改良格式,支持交错,可以在网页下载时,先呈现出图片的粗略外观后,再慢慢地呈现出完整的内容,渐进式JPG的文件 比标准JPG的文件要来得小。

③JPEG2000:新一代的影像压缩法,压缩品质更好,其压缩率比标准JPEG高约30%左右,同时支持有损 和无损压缩。一个极其重要的特征在于它能实现渐进传输,即先传输图像的轮廓,然后逐步传输数据,让图像由朦胧到清晰显示。

JPEG(Joint Photographic Experts Group)是联合图像专家小组的英文缩写。它由国际电话与电报咨询委员会CCITT(The International Telegraph and Telephone Consultative Committee)与国际标准化组织ISO于1986年联合成立的一个小组,负责制定静态数字图像的编码标准。

JPEG专家组开发了两种基本的压缩算法、两种数据编码方法、四种编码模式。具体如下:
压缩算法:
(1)有损的离散余弦变换(Discrete Cosine Transform,DCT);
(2)无损的预测技术压缩。
数据编码方法:
(1)哈夫曼编码;
(2)算术编码;
编码模式:
(1)基于DCT顺序模式:编/解码通过一次扫描完成
(2)基于DCT递进模式:编/解码需要多次扫描完成,扫描效果从粗糙到精细,逐级递进
(3)无损模式:基于DPCM,保证解码后完全精确恢复到原图像采样值
(4)层次模式:图像在多个空间多种分辨率进行编码,可以根据需要只对低分辨率数据作解码,放弃高分辨率信息

1.JPEG文件结构介绍

JPEG文件使用的数据存储方式有多种,最常用的格式称为JPEG文件交换格式(JPEG File Interchange Format,JFIF)。而JPEG文件大体上可以分成两个部分:标记码(Tag)和压缩数据。

标记码由两个字节构成,其前一个字节是固定值0xFF,后一个字节则根据不同意义有不同数值。在每个标记码之前还可以添加数目不限的无意义的0xFF填充,也就说连续的多个0xFF可以被理解为一个0xFF,并表示一个标记码的开始。而在一个完整的两字节的标记码后,就是该标记码对应的压缩数据流,记录了关于文件的诸种信息。

常用的标记有SOI、APP0、DQT、SOF0、DHT、DRI、SOS、EOI。

注意,SOI等都是标记的名称。在文件中,标记码是以标记代码形式出现。例如SOI的标记代码为0xFFD8,即在JPEG文件中的如果出现数据0xFFD8,则表示此处为一个SOI标记。

下面附录列出完整的JPEG定义的标记码表:

(1)SOI,Start of Image,图像开始
标记代码|2字节|固定值0xFFD8

(2)APP0,Application,应用程序保留标记0
标记代码|2字节|固定值0xFFE0
包含9个具体字段:
① 数据长度|2字节|①~⑨9个字段的总长度,即不包括标记代码,但包括本字段
② 标识符|5字节|固定值0x4A46494600,即字符串“JFIF0”
③ 版本号|2字节|一般是0x0102,表示JFIF的版本号1.2,可能会有其他数值代表其他版本
④ X和Y的密度单位|1字节|只有三个值可选
0:无单位;
1:点数/英寸;
2:点数/厘米
⑤ X方向像素密度|2字节|取值范围未知
⑥ Y方向像素密度|2字节|取值范围未知
⑦ 缩略图水平像素数目|1字节|取值范围未知
⑧ 缩略图垂直像素数目|1字节|取值范围未知
⑨ 缩略图RGB位图|长度可能是3的倍数|缩略图RGB位图数据

本标记段可以包含图像的一个微缩版本,存为24位的RGB像素。如果没有微缩图像(这种情况更常见),则字段⑦“缩略图水平像素数目”和字段⑧“缩略图垂直像素数目”的值均为0。

(3)APPn,Application,应用程序保留标记n,其中n=1~15(任选)
标记代码|2字节|固定值0xFFE1~0xFFF
包含2个具体字段:
① 数据长度|2字节|①~②2个字段的总长度,即不包括标记代码,但包括本字段
② 详细信息|数据长度-2字节|内容不定

(4)DQT,Define Quantization Table,定义量化表
标记代码|2字节|固定值0xFFDB
包含9个具体字段:
① 数据长度|2字节|字段①和多个字段②的总长度,即不包括标记代码,但包括本字段
② 量化表|数据长度|2字节
a)精度及量化表ID|1字节|
高4位:精度,只有两个可选值
0:8位;
1:16位
低4位:
量化表ID,取值范围为0~3
b)表项|64×(精度+1))字节|例如8位精度的量化表,其表项长度为64×(0+1)=64字节

本标记段中,字段②可以重复出现,表示多个量化表,但最多只能出现4次。

(5)SOF0,Start of Frame,帧图像开始
标记代码|2字节|固定值0xFFC0
包含9个具体字段:
① 数据长度|2字节|①~⑥六个字段的总长度,即不包括标记代码,但包括本字段
② 精度|1字节|每个数据样本的位数,通常是8位,一般软件都不支持 12位和16位
③ 图像高度|2字节|图像高度(单位:像素),如果不支持 DNL 就必须 >0
④ 图像宽度|2字节|图像宽度(单位:像素),如果不支持 DNL 就必须 >0
⑤ 颜色分量数|1字节|只有3个数值可选
1:灰度图;
3:YCrCb或YIQ;
4:CMYK
而JFIF中使用YCrCb,故这里颜色分量数恒为3
⑥颜色分量信息|颜色分量数×3字节(通常为9字节)
a)颜色分量ID|1字节
b)水平/垂直采样因子|1字节|
高4位:水平采样因子
低4位:垂直采样因子
c)量化表|1字节|当前分量使用的量化表的ID

本标记段中,字段⑥应该重复出现,有多少个颜色分量(字段⑤),就出现多少次(一般为3次)。

(6)DHT,Difine Huffman Table,定义哈夫曼表
标记代码|2字节|固定值0xFFC4
包含2个具体字段:
①数据长度|2字节|字段①和多个字段②的总长度,即不包括标记代码,但包括本字段
② 哈夫曼表|数据长度-2字节
a)表ID和表类型|1字节|
高4位:类型,只有两个值可选
0:DC直流;
1:AC交流
低4位:哈夫曼表ID,注意,DC表和AC表分开编码
b)不同位数的码字数量|16字节
c)编码内容|16个不同位数的码字数量之和(字节)

本标记段中,字段②可以重复出现(一般4次),也可以致出现1次。例如,Adobe Photoshop 生成的JPEG图片文件中只有1个DHT标记段,里边包含了4个哈夫曼表;而Macromedia Fireworks生成的JPEG图片文件则有4个DHT标记段,每个DHT标记段只有一个哈夫曼表。

(7)DRI,Define Restart Interval,定义差分编码累计复位的间隔
标记代码|2字节|固定值0xFFDD
包含2个具体字段:
①数据长度|2字节|固定值0x0004,①~②两个字段的总长度, 即不包括标记代码,但包括本字段
②MCU块的单元中的重新开始间隔|2字节|设其值为n,则表示每n个MCU块就有一个,RSTn标记。第一个标记是RST0,第二个是RST1等,RST7后再从RST0重复。

如果没有本标记段,或间隔值为0时,就表示不存在重开始间隔和标记RST

(8)SOS,Start of Scan,扫描开始 12字节
标记代码|2字节|固定值0xFFDA
包含2个具体字段:
①数据长度|2字节|①~④两个字段的总长度,即不包括标记代码,但包括本字段
②颜色分量数|1字节|应该和SOF中的字段⑤的值相同,即:
1:灰度图是;
3: YCrCb或YIQ;
4:CMYK。
而JFIF中使用YCrCb,故这里颜色分量数恒为3
③颜色分量信息
a) 颜色分量ID|1字节
b) 直流/交流系数表号|1字节|
高4位:直流分量使用的哈夫曼树编号
低4位:交流分量使用的哈夫曼树编号
④ 压缩图像数据
a)谱选择开始|1字节|固定值0x00
b)谱选择结束|1字节|固定值0x3F
c)谱选择|1字节|在基本JPEG中总为00

本标记段中,字段③应该重复出现,有多少个颜色分量(字段②),就出现多少次(一般为3次)。本段结束后,紧接着就是真正的图像信息了。图像信息直至遇到一个标记代码就自动结束,一般就是以EOI标记表示结束。

(9)EOI,End of Image,图像结束 2字节
标记代码|2字节|固定值0xFFD9

这里补充说明一下,由于在JPEG文件中0xFF具有标志性的意思,所以在压缩数据流(真正的图像信息)中出现0xFF,就需要作特别处理。具体方法是,在数据0xFF后添加一个没有意义的0x00。换句话说,如果在图像数据流中遇到0xFF,应该检测其紧接着的字符,如果是
1)0x00,则表示0xFF是图像流的组成部分,需要进行译码;
2)0xD9,则与0xFF组成标记EOI,则图像流结束,同时图像文件结束;
3)0xD0~0xD7,则组成RSTn标记,则要忽视整个RSTn标记,即不对当前0xFF和紧接的0xDn两个字节进行译码,并按RST标记的规则调整译码变量;
3)0xFF,则忽视当前0xFF,对后一个0xFF再作判断;
4)其他数值,则忽视当前0xFF,并保留紧接的此数值用于译码。

2.JPEG图像编码

在实际应用中,JPEG图像编码算法使用的大多是离散余弦变换、Huffman编码、顺序编码模式。这样的方式,被人们称为JPEG的基本系统。这里介绍的JPEG编码算法的流程,也是针对基本系统而言。基本系统的JPEG压缩编码算法一共分为11个步骤:颜色模式转换、采样、分块、离散余弦变换(DCT)、Zigzag 扫描排序、量化、DC系数的差分脉冲调制编码、DC系数的中间格式计算、AC系数的游程长度编码、AC系数的中间格式计算、熵编码。

(1)颜色模式转换

JPEG采用的是YCrCb颜色空间,而BMP采用的是RGB颜色空间,要想对BMP图片进行压缩,首先需要进行颜色空间的转换。YCrCb颜色空间中,Y代表亮度,Cr,Cb则代表色度和饱和度(也有人将Cb,Cr两者统称为色度),三者通常以Y,U,V来表示,即用U代表Cb,用V代表Cr。RGB和YCrCb之间的转换关系如下所示:

Y = 0.299R+0.587G+0.114B

Cb = -0.1687R-0.3313G+0.5B+128

Cr = 0.5R=0.418G-0.0813B+128

一般来说,C 值 (包括 Cb Cr) 应该是一个有符号的数字, 但这里通过加上128,使其变为8位的无符号整数,从而方便数据的存储和计算。反之:

R = Y+1.402(Cr-128)

G = Y-0.34414(Cb-128)-0.71414(Cr-128)

B = Y+1.772(Cb-128)

(2)采样

研究发现,人眼对亮度变换的敏感度要比对色彩变换的敏感度高出很多。因此,我们可以认为Y分量要比Cb,Cr分量重要的多。在BMP图片中,RGB三个分量各采用一个字节进行采样,也就是我们常听到的RGB888的模式;而JPEG图片中,通常采用两种采样方式:YUV411和YUV422,它们所代表的意义是Y,Cb,Cr三个分量的数据取样比例一般是4:1:1或者4:2:2(4:1:1含义就是:在2x2的单元中,本应分别有4个Y,4个U,4个V值,用12个字节进行存储。经过4:1:1采样处理后,每个单元中的值分别有4个Y、1个U、1个V,只要用6个字节就可以存储了)。这样的采样方式,虽然损失了一定的精度但也在人眼不太察觉到的范围内减小了数据的存储量。当然,JPEG格式里面也允许将每个点的U,V值都记录下来。

(3)分块

由于后面的DCT变换是是对8x8的子块进行处理的,因此,在进行DCT变换之前必须把源图象数据进行分块。源图象中每点的3个分量是交替出现的,先要把这3个分量分开,存放到3张表中去。然后由左及右,由上到下依次读取8x8的子块,存放在长度为64的表中,即可以进行DCT变换。注意,编码时,程序从源数据中读取一个8x8的数据块后,进行DCT变换,量化,编码,然后再读取、处理下一个8*8的数据块。

JPEG 编码是以每8x8个点为一个单位进行处理的. 所以如果原始图片的长宽不是 8 的倍数, 都需要先补成8的倍数, 使其可以进行一块块的处理。将原始图像数据分为8*8的数据单元矩阵之后,还必须将每个数值减去128,然后一一带入DCT变换公式,即可达到DCT变换的目的。图像的数据值必须减去128,是因为DCT公式所接受的数字范围是-128到127之间。

(4)离散余弦变换

DCT(Discrete Cosine Transform,离散余弦变换),是码率压缩中常用的一种变换编码方法。任何连续的实对称函数的傅里叶变换中只含有余弦项,因此,余弦变换同傅里叶变换一样具有明确的物理意义。DCT是先将整体图像分成N*N的像素块,然后针对N*N的像素块逐一进行DCT操作。需要提醒的是,JPEG的编码过程需要进行正向离散余弦变换,而解码过程则需要反向离散余弦变换。

正向离散余弦变换计算公式:

F(u,v)=c(u)c(v)∑N−1i=0∑N−1j=0f(i,j)cos[(2i+1)π2Nu]cos[(2j+1)π2Nv]

c(u)=1N−−√,当u=0

c(u)=2N−−√,当u≠0

反向离散余弦变换计算公式:

f(i,j)=∑N−1u=0∑N−1v=0c(u)c(v)F(u,v)cos[(2i+1)π2Nu]cos[(2j+1)π2Nv]

c(u)=1N−−√,当u=0

c(u)=2N−−√,当u≠0

这里的N是水平、垂直方向的像素数目,一般取值为8。8 * 8的二维像素块经过DCT操作之后,就得到了8 * 8的变换系数矩阵。这些系数,都有具体的物理含义,例如,U=0,V=0时的F(0,0)是原来的64个数据的均值,相当于直流分量,也有人称之为DC系数或者直流系数。随着U,V的增加,相另外的63个系数则代表了水平空间频率和垂直空间频率分量(高频分量)的大小,多半是一些接近于0的正负浮点数,我们称之为交流系数AC。DCT变换后的8*8的系数矩阵中,低频分量集中在矩阵的左上角。高频成分则集中在右下角。

由于大多数图像的高频分量比较小,相应的图像高频分量的DCT系数经常接近于0,再加上高频分量中只包含了图像的细微的细节变化信息,而人眼对这种高频成分的失真不太敏感,所以,可以考虑将这一些高频成分予以抛弃,从而降低需要传输的数据量。这样一来,传送DCT变换系数的所需要的编码长度要远远小于传送图像像素的编码长度。到达接收端之后通过反离散余弦变换就可以得到原来的数据,虽然这么做存在一定的失真,但人眼是可接受的,而且对这种微小的变换是不敏感的。

(5)Zigzag扫描排序

DCT 将一个 8x8 的数组变换成另一个 8x8 的数组. 但是内存里所有数据都是线形存放的, 如果我们一行行的存放这 64 个数字, 每行的结尾的点和下行开始的点就没有什么关系, 所以 JPEG 规定按如下图中的数字顺序依次保存和读取64 个DCT的系数值。

这样数列里的相邻点在图片上也是相邻的了。不难发现,这种数据的扫描、保存、读取方式,是从8*8矩阵的左上角开始,按照英文字母Z的形状进行扫描的,一般将其称之为Zigzag扫描排序。如下图所示:

(6)量化

图像数据转换为DCT频率系数之后,还要进行量化阶段,才能进入编码过程。量化阶段需要两个8*8量化矩阵数据,一个是专门处理亮度的频率系数,另一个则是针对色度的频率系数,将频率系数除以量化矩阵的值之后取整,即完成了量化过程。当频率系数经过量化之后,将频率系数由浮点数转变为整数,这才便于执行最后的编码。不难发现,经过量化阶段之后,所有的数据只保留了整数近似值,也就再度损失了一些数据内容。在JPEG算法中,由于对亮度和色度的精度要求不同,分别对亮度和色度采用不同的量化表。前者细量化,后者粗量化。

下图给出JPEG的亮度量化表和色度量化表,该量化表是从广泛的实验中得出的。当然,你也可以自定义量化表。


JPEG亮度量化表


JPEG色度量化表

这两张表依据心理视觉阀制作, 对 8bit 的亮度和色度的图象的处理效果不错。量化表是控制 JPEG 压缩比的关键,这个步骤除掉了一些高频量, 损失了很多细节信息。但事实上人眼对高频信号的敏感度远没有低频信号那么敏感。所以处理后的视觉损失很小,从上面的量化表也可以看出,低频部分采用了相对较短的量化步长,而高频部分则采用了相对较长的量化步长,这样做,也是为了在一定程度上得到相对清晰的图像和更高的压缩率。另一个重要原因是所有的图片的点与点之间会有一个色彩过渡的过程,而大量的图象信息被包含在低频率空间中,经过DCT处理后, 在高频率部分, 将出现大量连续的零。

(7)DC系数的差分脉冲调制编码

8*8的图像块经过DCT变换之后得到的DC系数有两个特点:

(1)系数的数值比较大;

(2)相邻的8*8图像块的DC系数值变化不大;

根据这两个特点,DC系数一般采用差分脉冲调制编码DPCM(Difference Pulse Code Modulation),即:取同一个图像分量中每个DC值与前一个DC值的差值来进行编码。对差值进行编码所需要的位数会比对原值进行编码所需要的位数少了很多。假设某一个8*8图像块的DC系数值为15,而上一个8*8图像块的DC系数为12,则两者之间的差值为3。

(8)DC系数的中间格式计算

JPEG中为了更进一步节约空间,并不直接保存数据的具体数值,而是将数据按照位数分为16组,保存在表里面。这也就是所谓的变长整数编码VLI。即,第0组中保存的编码位数为0,其编码所代表的数字为0;第1组中保存的编码位数为1,编码所代表的数字为-1或者1……,如下面的表格所示,这里,暂且称其为VLI编码表:

前面提到的那个DC差值为3的数据,通过查找VLI可以发现,整数3位于VLI表格的第2组,因此,可以写成(2)(3)的形式,该形式,称之为DC系数的中间格式。

(9)AC系数的行程长度编码(RLC)

量化之后的AC系数的特点是,63个系数中含有很多值为0的系数。因此,可以采用行程编码RLC(Run Length Coding)来更进一步降低数据的传输量。利用该编码方式,可以将一个字符串中重复出现的连续字符用两个字节来代替,其中,第一个字节代表重复的次数,第二个字节代表被重复的字符串。例如,(4,6)就代表字符串“6666”。但是,在JPEG编码中,RLC的含义就同其原有的意义略有不同。在JPEG编码中,假设RLC编码之后得到了一个(M,N)的数据对,其中M是两个非零AC系数之间连续的0的个数(即,行程长度),N是下一个非零的AC系数的值。采用这样的方式进行表示,是因为AC系数当中有大量的0,而采用Zigzag扫描也会使得AC系数中有很多连续的0的存在,如此一来,便非常适合于用RLC进行编码。

例如,现有一个字符串,如下所示:

57,45,0,0,0,0,23,0,-30,-8,0,0,1,000…..

经过RLC之后,将呈现出以下的形式:

(0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-8) ; (2,1) ; (0,0)

注意,如果AC系数之间连续0的个数超过16,则用一个扩展字节(15,0)来表示16连续的0。

(10)AC系数的中间格式

根据前面提到的VLI表格,对于前面的字符串:

(0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-8) ; (2,1) ; (0,0)

只处理每对数右边的那个数据,对其进行VLI编码: 查找上面的VLI编码表格,可以发现,57在第6组当中,因此,可以将其写成(0,6),57的形式,该形式,称之为AC系数的中间格式。

同样的(0,45)的中间格式为:(0,6),45;

(1,-30)的中间格式为:(1,5),-30;

(11)熵编码

在得到DC系数的中间格式和AC系数的中间格式之后,为进一步压缩图象数据,有必要对两者进行熵编码。JPEG标准具体规定了两种熵编码方式:Huffman编码和算术编码。JPEG基本系统规定采用Huffman编码(因为不存在专利问题),但JPEG标准并没有限制JPEG算法必须用Huffman编码方式或者算术编码方式。

Huffman编码:对出现概率大的字符分配字符长度较短的二进制编码,对出现概率小的字符分配字符长度较长的二进制编码,从而使得字符的平均编码长度最短。Huffman编码的原理请参考数据结构中的Huffman树或者最优二叉树。

Huffman编码时DC系数与AC系数分别采用不同的Huffman编码表,对于亮度和色度也采用不同的Huffman编码表。因此,需要4张Huffman编码表才能完成熵编码的工作。具体的Huffman编码采用查表的方式来高效地完成。然而,在JPEG标准中没有定义缺省的Huffman表,用户可以根据实际应用自由选择,也可以使用JPEG标准推荐的Huffman表。或者预先定义一个通用的Huffman表,也可以针对一副特定的图像,在压缩编码前通过搜集其统计特征来计算Huffman表的值。

下面我们举例来说明8*8图像子块经过DCT及量化之后的处理过程:

假设一个图像块经过量化以后得到以下的系数矩阵:

15 0 -1 0 0 0 0 0
-2 -1 0 0 0 0 0 0
-1 -1 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

显然,DC系数为15,假设前一个8*8的图像块的DC系数量化值为12,则当前DC系统同上一个DC系数之间的差值为3,通过查找VLI编码表,可以得到DC系数的中间格式为(2)(3),这里的2代表后面的数字(3)的编码长度为2位;之后,通过Zigzag扫描之后,遇到第一个非0的AC系数为-2,遇到0的个数为1,AC系数经过RLC编码后可表示为(1,-2),通过查找VLI表发现,-2在第2组,因此,该AC系数的中间格式为(1,2)-2;
其余的点类似,可以求得这个8*8子块熵编码的中间格式为
(DC)(2)(3);AC(1,2)(-2),(0,1)(-1),(0,1)(-1),(0,1)(-1),(2,1)(-1),(EOB)(0,0)
对于DC系数的中间格式(2)(3)而言,数字2查DC亮度Huffman表得到011,数字3通过查找VLI编码表得到其被编码为11;
对于AC系数的中间格式(1,2)(-2)而言,(1,2)查AC亮度Huffman表得到11011,-2通过查找VLI编码表得到其被编码为01;

对于AC系数的中间格式(0,1)(-1)而言,(0,1)查AC亮度Huffman表得到00,数字-1通过查找VLI编码表得到其被编码为0;

对于AC系数的中间格式(2,1)(1)而言,(2,1)查AC亮度Huffman表得到11100,数字-1通过查找VLI编码表得到其被编码为0;

对于AC系数的中间格式(0,0)而言,查AC亮度Huffman表得到1010;
因此,最后这个8 * 8子块亮度信息压缩后的数据流为01111,1101101,000,000,000,111000,1010。总共31比特,其压缩比是64 * 8/31=16.5,大约每个像素用半个比特。

JPEG解码过程在此不再赘述,与编码过程对称。

三.BMP格式

BMP(Bitmap-File)图形文件是Windows采用的图形文件格式,在Windows环境下运行的所有图象处理软件都支持BMP图象文件格式。Windows系统内部各图像绘制操作都是以BMP为基础的。Windows 3.0以前的BMP图文件格式与显示设备有关,因此把这种BMP图象文件格式称为设备相关位图DDB(device-dependent bitmap)文件格式。Windows 3.0以后的BMP图象文件与显示设备无关,因此把这种BMP图象文件格式称为设备无关位图DIB(device-independent bitmap)格式(注:Windows 3.0以后,在系统中仍然存在DDB位图,象BitBlt()这种函数就是基于DDB位图的,只不过如果你想将图像以BMP格式保存到磁盘文件中时,微软极力推荐你以DIB格式保存),目的是为了让Windows能够在任何类型的显示设备上显示所存储的图象。BMP位图文件默认的文件扩展名是BMP或者bmp(有时它也会以.DIB或.RLE作扩展名)。

1.BMP格式结构

BMP文件的数据按照从文件头开始的先后顺序分为四个部分:

(1)位图文件头(bmp file header): 提供文件的格式、大小等信息
(2)位图信息头(bitmap information):提供图像数据的尺寸、位平面数、压缩方式、颜色索引等信息
(3)调色板(color palette):可选,如使用索引来表示图像,调色板就是索引与其对应的颜色的映射表
(4)位图数据(bitmap data):图像数据区

数据段名称 大小(byte) 开始地址 结束地址
位图文件头(bitmap-file header) 14 0000h 000Dh
位图信息头(bitmap-information header) 40 000Eh 0035h
调色板(color table) 由biBitCount决定 0036h 未知
图片点阵数据(bitmap data) 由图片大小和颜色定 未知 未知

2.BMP文件头

BMP文件头结构体定义如下:

typedef struct tagBITMAPFILEHEADER
{
UINT16 bfType; //2Bytes,必须为"BM",即0x424D 才是Windows位图文件
DWORD bfSize; //4Bytes,整个BMP文件的大小
UINT16 bfReserved1; //2Bytes,保留,为0
UINT16 bfReserved2; //2Bytes,保留,为0
DWORD bfOffBits; //4Bytes,文件起始位置到图像像素数据的字节偏移量
} BITMAPFILEHEADER;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
变量名 地址偏移 大小 作用说明
bfType 0000h 2Bytes 文件标识符,必须为”BM”,即0x424D才是Windows位图文件
bfSize 0002h 4Bytes 整个BMP文件的大小(以位B为单位)
bfReserved1 0006h 2Bytes 保留,必须设置为0
bfReserved2 0008h 2Bytes 保留,必须设置为0
bfOffBits 000Ah 4Bytes 说明从文件头0000h开始到图像像素数据的字节偏移量(以字节Bytes为单位),以为位图的调色板长度根据位图格式不同而变化,可以用这个偏移量快速从文件中读取图像数据

3.BMP信息头

BMP信息头结构体定义如下:

typedef struct _tagBMP_INFOHEADER
{
DWORD biSize; //4Bytes,INFOHEADER结构体大小,存在其他版本I NFOHEADER,用作区分
LONG biWidth; //4Bytes,图像宽度(以像素为单位)
LONG biHeight; //4Bytes,图像高度,+:图像存储顺序为Bottom2Top,-:Top2Bottom
WORD biPlanes; //2Bytes,图像数据平面,BMP存储RGB数据,因此总为1
WORD biBitCount; //2Bytes,图像像素位数
DWORD biCompression; //4Bytes,0:不压缩,1:RLE8,2:RLE4
DWORD biSizeImage; //4Bytes,4字节对齐的图像数据大小
LONG biXPelsPerMeter; //4 Bytes,用象素/米表示的水平分辨率
LONG biYPelsPerMeter; //4 Bytes,用象素/米表示的垂直分辨率
DWORD biClrUsed; //4 Bytes,实际使用的调色板索引数,0:使用所有的调色板索引
DWORD biClrImportant; //4 Bytes,重要的调色板索引数,0:所有的调色板索引都重要
}BMP_INFOHEADER;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

BMP信息头数据表如下:

变量名 地址偏移 大小 作用说明
biSize 000Eh 4Bytes BNP信息头即BMP_INFOHEADER结构体所需要的字节数(以字节为单位)
biWidth 0012h 4Bytes 说明图像的宽度(以像素为单位)
biHeight 0016h 4Bytes 说明图像的高度(以像素为单位)。这个值还有一个用处,指明图像是正向的位图还是倒向的位图,该值是正数说明图像是倒向的即图像存储是由下到上;该值是负数说明图像是倒向的即图像存储是由上到下。大多数BMP位图是倒向的位图,所以此值是正值。
biPlanes 001Ah 2Bytes 为目标设备说明位面数,其值总设置为1
biBitCount 001Ch 2Bytes 说明一个像素点占几位(以比特位/像素位单位),其值可为1,4,8,16,24或32
biCompression 001Eh 4Bytes 说明图像数据的压缩类型,取值范围为:
0 BI_RGB 不压缩(最常用)
1 BI_RLE8 8比特游程编码(BLE),只用于8位位图
2 BI_RLE4 4比特游程编码(BLE),只用于4位位图
3 BI_BITFIELDS比特域(BLE),只用于16/32位位图
biSizeImage 0022h 4Bytes 说明图像的大小,以字节为单位。当用BI_RGB格式时,总设置为0
biXPelsPerMeter 0026h 4Bytes 说明水平分辨率,用像素/米表示,有符号整数
biYPelsPerMeter 002Ah 4Bytes 说明垂直分辨率,用像素/米表示,有符号整数
biClrUsed 002Eh 4Bytes 说明位图实际使用的调色板索引数,0:使用所有的调色板索引
biClrImportant 0032h 4Bytes 说明对图像显示有重要影响的颜色索引的数目,如果是0,表示都重要。

4.BMP调色板

BMP调色板结构体定义如下:

typedef struct _tagRGBQUAD
{
BYTE rgbBlue; //指定蓝色强度
BYTE rgbGreen; //指定绿色强度
BYTE rgbRed; //指定红色强度
BYTE rgbReserved; //保留,设置为0
} RGBQUAD;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

1,4,8位图像才会使用调色板数据,16,24,32位图像不需要调色板数据,即调色板最多只需要256项(索引0 - 255)。
颜色表的大小根据所使用的颜色模式而定:2色图像为8字节;16色图像位64字节;256色图像为1024字节。其中,每4字节表示一种颜色,并以B(蓝色)、G(绿色)、R(红色)、alpha(32位位图的透明度值,一般不需要)。即首先4字节表示颜色号1的颜色,接下来表示颜色号2的颜色,依此类推。

颜色表中RGBQUAD结构数据的个数有biBitCount来确定,当biBitCount=1,4,8时,分别有2,16,256个表项。

当biBitCount=1时,为2色图像,BMP位图中有2个数据结构RGBQUAD,一个调色板占用4字节数据,所以2色图像的调色板长度为2*4为8字节。

当biBitCount=4时,为16色图像,BMP位图中有16个数据结构RGBQUAD,一个调色板占用4字节数据,所以16像的调色板长度为16*4为64字节。

当biBitCount=8时,为256色图像,BMP位图中有256个数据结构RGBQUAD,一个调色板占用4字节数据,所以256色图像的调色板长度为256*4为1024字节。

当biBitCount=16,24或32时,没有颜色表。

5.BMP图像数据区

位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:
当biBitCount=1时,8个像素占1个字节;
当biBitCount=4时,2个像素占1个字节;
当biBitCount=8时,1个像素占1个字节;
当biBitCount=24时,1个像素占3个字节;
Windows规定一个扫描行所占的字节数必须是4的倍数(即以long为单位),不足的以0填充,
一个扫描行所占的字节数计算方法:
DataSizePerLine= (biWidth* biBitCount+31)/8;
// 一个扫描行所占的字节数
DataSizePerLine= DataSizePerLine/4*4; // 字节数必须是4的倍数
位图数据的大小(不压缩情况下):
DataSize= DataSizePerLine* biHeight;

颜色表接下来位为位图文件的图像数据区,在此部分记录着每点像素对应的颜色号,其记录方式也随颜色模式而定,既2色图像每点占1位(8位为1字节);16色图像每点占4位(半字节);256色图像每点占8位(1字节);真彩色图像每点占24位(3字节)。所以,整个数据区的大小也会随之变化。究其规律而言,可的出如下计算公式:图像数据信息大小=(图像宽度图像高度记录像素的位数)/8。

四.JIF格式

GIF是图像交换格式(Graphics Interchange Format)的简称,它是由美国CompuServe公司在1987年所提出的图像文件格式,它最初的目的是希望每个BBS的使用者能够通过GIF图像 文件轻易存储并交换图像数据,这也就是它为什么被称为图像交换格式的原因了。

 GIF文件格式采用了一种经过改进的LZW压缩算法,通常我们称 之为GIF-LZW算法。这是一种无损的压缩算法,压缩效率也比较高,并且GIF支持在一幅GIF文件中存放多幅彩色图像,并且可以按照一定的顺序和时间 间隔将多幅图像依次读出并显示在屏幕上,这样就可以形成一种简单的动画效果。尽管GIF最多只支持256色,但是由于它具有极佳的压缩效率并且可以做成动 画而早已被广泛接纳采用。下面笔者详细介绍GIF文件的格式。
 
 GIF图像文件是以块的形式来存储图像信息,其中的块又称为区域结构。按照其中 块的特征又可以将所有的块分成三大类,分别是控制块(Control Block)、图像描述块(Graphic Rendering Block)和特殊用途块(Special Purpose Block)。控制块包含了控制数据流的处理以及硬件参数的设置,其成员主要包括文件头信息、逻辑屏幕描述块、图像控制扩充块和文件结尾块。图像描述块包 含了在显示设备上描述图像所需的信息,其成员包括图像描述块、全局调色板、局部调色板、图像压缩数据和图像说明扩充块。特殊用途块包含了与图像数据处理无直接关系的信息,其成员包括图像注释扩充块和应用程序扩充块。下面详细介绍每一个块的详细结构。
 
1. 文件头信息

GIF的文件头只有六个字节,其结构定义如下:

typedef struct gifheader
{
BYTE bySignature[3];
BYTE byVersion[3];
} GIFHEADER;
  • 1
  • 2
  • 3
  • 4
  • 5

   其中,bySignature为GIF文件标示码,其固定值为“GIF”,使用者可以通过该域来判断一个图像文件是否是GIF图像格式的文件。 byVersion表明GIF文件的版本信息。其取值固定为“87a”和“89a”。分别表示GIF文件的版本为GIF87a或GIF89a。这两个版本 有一些不同,GIF87a公布的时间为1987年,该版本不支持动画和一些扩展属性。GIF89a是1989年确定的一个版本标准,只有89a版本才支持 动画、注释扩展和文本扩展。

2. 逻辑屏幕描述块

 逻辑屏幕(Logical Screen)是一个虚拟屏幕(Virtual Screen),它相当于画布,所有的操作都是在它的基础上进行的,同时它也决定了图像的长度和宽度。逻辑屏幕描述块共占有七个字节,其具体结构定义如下:

typedef struct gifscrdesc
{
WORD wWidth;
WORD wDepth;
struct globalflag
{
BYTE PalBits : 3;
BYTE SortFlag : 1;
BYTE ColorRes : 3;
BYTE GlobalPal : 1;
} GlobalFlag;
BYTE byBackground;
BYTE byAspect;
} GIFSCRDESC;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

   其中,wWidth用来指定逻辑屏幕的宽度,wDepth用来指定逻辑屏幕的高度,glaobalflag为全域性数据,它的总长度为一个字节,其中前 三位(第0位到第2位)指定全局调色板的位数,可以通过该值来计算全局调色板的大小。第3位表明全局调色板中的RGB颜色值是否按照使用率进行从高到底的 次序排序的。第4到第6位指定图像的色彩分辨率。第7位指明GIF文件中是否具有全局调色板,其值取1表示有全局调色板,为0表示没有全局调色板。一个 GIF文件可以有全局调色板也可以没有全局调色板,如果定义了全局调色板并且没有定义某一幅图像的局部调色板,则本幅图像采用全局调色板;如果某一幅图像 定义的自己的局部调色板,则该幅图像使用自己的局部调色板。如果没有定义全局调色板,则GIF文件中的每一幅图像都必须定义自己的局部调色板。全局调色板 必须紧跟在逻辑屏幕描述块的后面,其大小由GlobalFlag.PalBits决定,其最大长度为768(3*256)字节。全局调色板的数据是按照 RGBRGB…..RGB的方式存储的。byBackground用来指定逻辑屏幕的背景颜色,也就相当于是画布的颜色。当图像长宽小于逻辑屏幕的大小 时,未被图像覆盖部分的颜色值由该值对应的全局调色板中的索引颜色值确定。如果没有全局调色板,该值无效,默认背景颜色为黑色。byAspect用来指定 逻辑屏幕的像素的长宽比例。

3. 图像描述块

  一幅GIF图像文件中可以存储多幅图像,并且这些图像没有固定的存放次序。为了区分两幅 图像,GIF采用了一个字节的识别码(Image Separator)来判断下面的数据是否是图像描述块。图像描述块以0x2C开始,定义紧接着它的图像的性质,包括图像相对于逻辑屏幕边界的偏移量、图 像大小以及有无局部调色板和调色板的大小。图像描述块由10个字节组成:

typedef struct gifimage
  {
   WORD wLeft;
   WORD wTop;
   WORD wWidth;
   WORD wDepth;
   struct localflag
   {
   BYTE PalBits : 3;
   BYTE Reserved : 2;
   BYTE SortFlag : 1;
   BYTE Interlace : 1;
   BYTE LocalPal : 1;
   } LocalFlag;
   } GIFIMAGE;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

   其中,wLeft用来指定图像相对逻辑屏幕左上角的X坐标,以象素为单位。wTop用来指定图像相对逻辑屏幕左上角的Y坐标。wWdith和 wDepth分别用来指定图像的宽度和高度。LocalFlag用来指定区域性数据,也就是具体一幅图像的属性。LocalFlag的总长度为一个字节, 其中的前三位用来指定局部调色板的位数,可以根据该值来计算局部调色板的大小。第4位到第5位为保留位,没有使用,其值固定为0。第6位指明局部调色板中 的RGB颜色值是否经过排序,其值为1表示调色板中的RGB颜色值是按照其使用率从高到底的次序进行排序。第7位表示GIF图像是否以交错方式存储,其取 值为1表示以交错的方式进行存储。当图像是按照交错方式存储时,其图像数据的处理可以分为4个阶段:第一阶段从第0行开始,每次间隔8行进行处理;第二阶 段从第4行开始,每次间隔8行进行处理;第三阶段从第2行开始,每次间隔4行进行处理;第四阶段从第1行开始,每次间隔2行进行处理,这样当完成第一阶段 时就可以看到图像的概貌,当处理完第二阶段时,图像会变得清晰一些;当处理完第三阶段时,图像处理完成一半,清晰效果也进一步增强,当完成第四阶段,图像 处理完毕,显示出完整清晰的整幅图像。以交错方式存储是GIF文件格式的一个重要的特点,也是GIF文件格式的一个重要的优点。以交错方式存储的图像的好 处就是无需将整个图像文件解压完成就可以看到图像的概貌,这样可以减少用户的等待时间。第8位指明GIF图像是否含有局部调色板,如果含有局部调色板,则 局部调色板的内容应当紧跟在图像描述块的后面。

4. 图像压缩数据

 图像压缩数据是按照GIF-LZW压缩编码后存储于图像压缩数据块 中的。GIF-LZW编码是一种经过改良的LZW编码方式,它是一种无损压缩的编码方法。GIF-LZW编码方法是将原始数据中的重复字符串建立一个字符 串表,然后用该重复字符串在字符串表中的索引来替代原始数据以达到压缩的目的。由于GIF-LZW压缩编码的需要,必须首先存储GIF-LZW的最小编码 长度以供解码程序使用,然后再存储编码后的图像数据。编码后的图像数据是一个个数据子块的方式存储的,每个数据子块的最大长度为256字节。数据子块的第 一个字节指定该数据子块的长度,接下来的数据为数据子块的内容。如果某个数据子块的第一个字节数值为0,即该数据子块中没有包含任何有用数据,则该子块称 为块终结符,用来标识数据子块到此结束。
 
5. 图像控制扩充块

 图像控制扩充块是可选的,只应用于89a版本,它描述了与图像控制相关 的参数。一般情况下,图像控制扩充块位于一个图像块(包括图像标识符、局部颜色列表和图像数据)或文本扩展块的前面,用来控制跟在它后面的第一个图像(或 文本)的渲染(Render)形式,组成结构如下:
  

typedef struct gifcontrol
  {
   BYTE byBlockSize;
   struct flag
   {
   BYTE Transparency : 1;
   BYTE UserInput : 1;
   BYTE DisposalMethod : 3;
   BYTE Reserved : 3;
   } Flag;
   WORD wDelayTime;
   BYTE byTransparencyIndex;
   BYTE byTerminator;
  } GIFCONTROL;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

  其中,byBlockSize用来指定该图像控制扩充块的长度,其取值固定为4。Flag用来描述图像控制相关数据,它的长度为1个字节。它的第0位用 来指定图像中是否具有透明性的颜色,如果该位为1,这表明图像中某种颜色具有透明性,该颜色由参数byTransparencyIndex指定。第一位用 来判断在显示一幅图像后,是否需要用户输入后再进行下一个动作。如果该位为1,则表示应用程序在进行下一个动作之前需要用户输入。第2-4位用来指定图像 显示后的处理方式,当该值为0时,表示没有指定任何处理方式;当该值为1时,表明不进行任何处理动作;当该值为2时,表明图像显示后以背景色擦去;当该值 为3时,表明图像显示后恢复原先的背景图像。第5-7位为保留位,没有任何含义,固定为0。wDelayTime用来指定应用程序进行下一步操作之前延迟 的时间,单位为0.01秒。如果Flag.UserInput和wDelayTime都设定了,则以先发者为主,如果没有到指定的延迟时间即有用户输入, 则应用程序直接进行下一步操作。如果到达延迟时间后还没有用户输入,应用程序也直接进入下一步操作。byTransparenceIndex用来指定图像 中透明色的颜色索引,指定的透明色将不在显示设备上显示。byTerminator为块终结符,其值固定为0。

6. 图像说明扩充块

图像说明扩充块又可以称为图像文本扩展块,它用来绘制一个简单的文本图像,这一部分由用来绘制的纯文本数据(7位的 ASCII字符)和控制绘制的参数等组成。绘制文本借助于一个文本框(Text Grid)来定义边界,在文本框中划分多个单元格,每个字符占用一个单元,绘制时按从左到右、从上到下的顺序依次进行,直到最后一个字符或者占满整个文本 框(之后的字符将被忽略,因此定义文本框的大小时应该注意到是否可以容纳整个文本),绘制文本的颜色使用全局颜色列表,没有则可以使用一个已经保存的前一 个颜色列表。另外,图形文本扩展块也属于图形块(Graphic Rendering Block),可以在它前面定义图形控制扩展对它的表现形式进一步修改。图像说明扩充块的组成:

typedef struct gifplaintext
  {
   BYTE byBlockSize;
   WORD wTextGridLeft;
   WORD wTextGridTop;
   WORD wTextGridWidth;
   WORD wTextGridDepth;
   BYTE byCharCellWidth;
   BYTE byCharCellDepth;
   BYTE byForeColorIndex;
   BYTE byBackColorIndex;
  } GIFPLAINTEXT;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

  其中,byBlockSize用来指定该图像扩充块的长度,其取值固定为13。wTextGridLeft用来指定文字显示方格相对于逻辑屏幕左上角的 X坐标(以像素为单位)。wTextGridTop用来指定文字显示方格相对于逻辑屏幕左上角的Y坐标。wTextGridWidth用来指定文字显示方 格的宽度。wTextGridDepth用来指定文字显示方格的高度。byCharCellWidth用来指定字符的宽度, byCharCellDepth用来指定字符的高度。byForeColorIndex用来指定字符的前景色,byBackColorIndex用来指定 字符的背景色。
 
7. 图像注释扩充块

 图像注释扩充块包含了图像的文字注释说明,可以用来记录图形、版权、描述等任何的非图形和控制的 纯文本数据(7位的ASCII字符),注释扩展并不影响对图象数据流的处理,解码器完全可以忽略它。存放位置可以是数据流的任何地方,最好不要妨碍控制和 数据块,推荐放在数据流的开始或结尾。在GIF中用识别码0xFE来判断一个扩充块是否为图像注释扩充块。图像注释扩充块中的数据子块个数不限,必须通过 块终结符来判断该扩充块是否结束。

8. 应用程序扩充块

 应用程序扩充块包含了制作该GIF图像文件的应用程序的信息,GIF中用识别码0xFF来判断一个扩充块是否为应用程序扩充块。它的结构定义如下:

typedef struct gifapplication
  {
   BYTE byBlockSize;
   BYTE byIdentifier[8];
   BYTE byAuthentication[3];
  } GIFAPPLICATION;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

 其中,byBlockSize用来指定该应用程序扩充块的长度,其取值固定为12。byIdentifier用来指定应用程序名称。byAuthentication用来指定应用程序的识别码。
 
9. 文件结尾块

 文件结尾块为GIF图像文件的最后一个字节,其取值固定为0x3B。

总结

PNG格式图片分析

PNG这种图片格式包括了许多子类,但是在实践中大致可以分为256色的PNG(PNG8)和全色的PNG(PNG24、 PNG32),你完成可以用256色的PNG代替GIF,用全色的PNG代替JPEG

透明性:

PNG是完全支持alpha透明的(透明,半透明,不透明)

动画:

它不支持动画

无损耗性:

PNG是一种无损耗的图像格式,这也意味着你可以对PNG图片做任何操作也不会使 得图像质量产生损耗。这也使得PNG可以作为JPEG编辑的过渡格式
水平扫描像GIF一样,PNG也是水平扫描的,这样意味着水平重复颜色比垂直重复颜色的图片更小

间隔渐进显示:

它支持间隔渐进显示,但是会造成图片大小变得更大

优点:

  * 支持256色调色板技术以产生小体积文件
  * 最高支持48位真彩色图像以及16位灰度图像。
  * 支持Alpha通道的半透明特性。
  * 支持图像亮度的gamma校正信息。
  * 支持存储附加文本信息,以保留图像名称、作者、版权、创作时间、注释等信息。
  * 使用无损压缩。
  * 渐近显示和流式读写,适合在网络传输中快速显示预览效果后再展示全貌。
  * 使用CRC循环冗余编码防止文件出错。
  * 最新的PNG标准允许在一个文件内存储多幅图像。

缺点:

  但也有一些软件不能使用适合的预测,而造成过分臃肿的PNG文件。

JPEG格式图片特点

透明性、动画:

它并不支持透明,也不支持动画。

损耗性:

除了一些比如说旋转(仅仅是90、180、270度旋转),裁切,从标准类型到先进类型,编辑图片的原数据之外,所有其它操作对JPEG图像的处理 都会使得它的质量损失。所以我们在编辑过程一般用PNG作为过渡格式。

隔行渐进显示:

它支持隔行渐进显示(但是ie浏览器并不支持这个属性,但是ie会在整个图像信息完全到达的时候显示)。
由上可以看出JPEG是最适web上面的摄影图片和数字照相机中。

优点:

  JPEG/JFIF是最普遍在万维网(World Wide Web)上被用来储存和传输照片的格式。JPEG在色调及颜色平滑变化的相片或是写实绘画(painting)上可以达到它最佳的效果。在这种情况下,它通常比完全无失真方法作得更好,仍然可以产生非常好看的影像(事实上它会比其他一般的方法像是GIF产生更高品质的影像,因为GIF对于线条绘画(drawing)和图示的图形是无失真,但针对全彩影像则需要极困难的量化)。

缺点:

  它并不适合于线条绘图(drawing)和其他文字或图示(iconic)的图形,因为它的压缩方法用在这些图形的型态上,会得到不适当的结果;

GIF格式图片的特点

透明性:

Gif是一种布尔透明类型,既它可以是全透明,也可以是全不透明,但是它并没有半透明(alpha 透明)。

动画:

Gif这种格式支持动画。

无损耗性:

Gif是一种无损耗的图像格式,这也意味着你可以对gif图片做任何操作也不会使 得图像质量产生损耗。

水平扫描:

Gif是使用了一种叫作LZW的算法进行压缩的,当压缩gif的过程中,像素是由上到下水平压缩的,这也意味着同等条件下,横向的gif图片比竖向 的gif图片更加小。例如500*10的图片比10*500的图片更加小

间隔渐进显示:

Gif支持可选择性的间隔渐进显示

由以上特点看出只有256种颜色的gif图片不适合照片,但它适合对颜色要求不高的图形(比如说图标,图表等),它并不是最优的选择

优点:

  1. 优秀的压缩算法使其在一定程度上保证图像质量的同时将体积变得很小。
  2. 可插入多帧,从而实现动画效果。
  3. 可设置透明色以产生对象浮现于背景之上的效果。

缺点:

  由于采用了8位压缩,最多只能处理256种颜色(2的8次方),故不宜应用于真彩图像。

BMP格式图片的特点

透明性:

32位BMP有透明分量,可以通过添加通道使图片具有透明效果

动画:

不支持动画

无损耗性:

它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP文件所占用的空间很大

优点:

由于BMP文件格式是Windows环境中交换与图有关的数据的一种标准,因此在Windows环境中运行的图形图像软件都支持BMP图像格式。

BMP格式的图像,其优点是不采用任何压缩,无损,颜色准确,有2色、16色、256色、真彩色各种选择。

缺点:

缺点就是文件占用的空间很大,不支持文件压缩,不适用于 Web 页,不受 Web 浏览器支持。

PNG,JPEG,BMP,JIF图片格式详解及其对比的更多相关文章

  1. BMP格式详解

    BMP格式详解 BMP文件格式详解(BMP file format) BMP文件格式,又称为Bitmap(位图)或是DIB(Device-Independent Device,设备无关位图),是Win ...

  2. java分享第十五天(log4j 格式详解)

    log4j 格式详解  log4j.rootLogger=日志级别,appender1, appender2, -. 日志级别:ALL<DEBUG<INFO<WARN<ERRO ...

  3. php 序列化(serialize)格式详解

    1.前言 PHP (从 PHP 3.05 开始)为保存对象提供了一组序列化和反序列化的函数:serialize.unserialize.不过在 PHP 手册中对这两个函数的说明仅限于如何使用,而对序列 ...

  4. Java字节码(.class文件)格式详解(一)

    原文链接:http://www.blogjava.net/DLevin/archive/2011/09/05/358033.html 小介:去年在读<深入解析JVM>的时候写的,记得当时还 ...

  5. binlog之四:mysql中binlog_format模式与配置详解,binlog的日志格式详解

    mysql复制主要有三种方式:基于SQL语句的复制(statement-based replication, SBR),基于行的复制(row-based replication, RBR),混合模式复 ...

  6. 以太网帧格式、IP数据报格式、TCP段格式+UDP段格式 详解

    转载:http://www.cnblogs.com/lifan3a/articles/6649970.html 以太网帧格式.IP数据报格式.TCP段格式+UDP段格式 详解   1.ISO开放系统有 ...

  7. FLV视频封装格式详解

    FLV视频封装格式详解 分类: FFMpeg编解码 2012-04-04 21:13 1378人阅读 评论(2) 收藏 举报 flvheaderaudiovideocodecfile 目录(?)[-] ...

  8. Linux下 ps -ef 和 ps aux 的区别及格式详解

    原文:https://www.cnblogs.com/5201351/p/4206461.html Linux下ps -ef和ps aux的区别及格式详解 Linux下显示系统进程的命令ps,最常用的 ...

  9. WAL日志文件名称格式详解

    转自:http://blog.osdba.net/534.html WAL日志文件名称格式详解 PostgreSQL的WAL日志文件在pg_xlog目录下,一般情况下,每个文件为16M大小: osdb ...

随机推荐

  1. luogu2577/bzoj1899 午餐 (贪心+dp)

    首先,应该尽量让吃饭慢的排在前面,先按这个排个序 然后再来决定每个人到底去哪边 设f[i][j]是做到了第i个人,然后1号窗口目前的总排队时间是j,目前的最大总时间 有这个i和j的话,再预处理出前i个 ...

  2. Looper Handler Mssage

    1. 一个Handler只有一个队列;2. 在调用Handler.post(Runnable runnable)方法时,会将runnable封装成一个Message;3. 在队列执行时,会判断当前的M ...

  3. EFCodeFirst快速搭建入门

    EFCodeFirst快速搭建入门 1.新建Model类库项目. 添加EntityFramework.dll的引用. 编写实体类Course,Student. namespace EFCodeFirs ...

  4. A1028. List Sorting

    Excel can sort records according to any column. Now you are supposed to imitate this function. Input ...

  5. 树链剖分&dfs序

    树上问题 很多处理区间的问题(像是RMQ,区间修改).可以用线段树,树状数组,ST表这些数据结构来维护.但是如果将这些问题挪到了树上,就不能直接用这些数据结构来处理了.这时就用到了dfs序和树链剖分. ...

  6. 2636652995 揭秘骗子qq

    3042952272636652995755610392020068008这是个骗子群526875508,群里都是群主的小号,付钱之后不给东西,还在群里维护骗子的利益,很明显了.都是骗子小号了,付完整 ...

  7. 【Maven】基础概念、仓库、构建与部属

    1.常见的自动化构建工具有: make.ant.maven.gradle,gradle是目前最新的,maven是目前最常用的. Eclipse是一种半自动化构建工具,主要体现在把:java文件-> ...

  8. nxlog windows安装部署

    nxlog 介绍 nxlog 是用 C 语言写的一个跨平台日志收集处理软件.其内部支持使用 Perl 正则和语法来进行数据结构化和逻辑判断操作.不过,其最常用的场景.是在 windows 服务器上,作 ...

  9. Python基础【day03】:入门知识拾遗(八)

    本节内容 1.作用域 2.三元运算 3.进制 一.作用域 对于变量的作用域,执行声明并在内存中存在,该变量就可以在下面的代码中使用. 1 2 3 if 1==1:     name = 'wupeiq ...

  10. Hibernate的实体类中为什么要继承Serializable?

    确切的说应该是对象的序列化,一般程序在运行时,产生对象,这些对象随着程序的停止运行而消失,但如果我们想把某些对象(因为是对象,所以有各自 不同的特性)保存下来,在程序终止运行后,这些对象仍然存在,可以 ...