图片文件格式汇编

BMP文件格式

BMP文件格式
6.1 BMP文件格式

6.1.1 简介

位图文件(Bitmap-File,BMP)格式是Windows采用的图像文件存储格式,在Windows环境下运行的所有图像处理软件都支持这种格式。Windows 3.0以前的BMP位图文件格式与显示设备有关,因此把它称为设备相关位图(device-dependent bitmap,DDB)文件格式。Windows 3.0以后的BMP位图文件格式与显示设备无关,因此把这种BMP位图文件格式称为设备无关位图(device-independent bitmap,DIB)格式,目的是为了让Windows能够在任何类型的显示设备上显示BMP位图文件。BMP位图文件默认的文件扩展名是BMP或者bmp。

6.1.2 文件结构

位图文件可看成由4个部分组成:位图文件头(bitmap-file header)、位图信息头(bitmap-information header)、彩色表(color table)和定义位图的字节阵列,它们的名称和符号如表6-01所示。

表6-01 BMP图像文件组成部分的名称和符号

位图文件的组成

结构名称

符号

位图文件头(bitmap-file header)

BITMAPFILEHEADER

bmfh

位图信息头(bitmap-information header)

BITMAPINFOHEADER

bmih

彩色表(color table)

RGBQUAD

aColors[]

图像数据阵列字节

BYTE

aBitmapBits[]

位图文件结构可综合在表6-02中。

表6-02 位图文件结构内容摘要

 

偏移量

域的名称

大小

内容

 

 

 

图像文件

0000h

标识符(Identifier)

2 bytes

两字节的内容用来识别位图的类型:

BM : Windows 3.1x, 95, NT, 

BA :OS/2 Bitmap Array

CI :OS/2 Color Icon

CP :OS/2 Color Pointer

IC : OS/2 Icon

PT :OS/2 Pointer

 

0002h

File Size

1 dword

用字节表示的整个文件的大小

 

0006h

Reserved

1 dword

保留,设置为0

 

000Ah

Bitmap Data Offset

1 dword

从文件开始到位图数据开始之间的数据(bitmap data)之间的偏移量

 

000Eh

Bitmap Header Size

1 dword

位图信息头(Bitmap Info Header)的长度,用来描述位图的颜色、压缩方法等。下面的长度表示:

28h - Windows 3.1x, 95, NT, 

0Ch - OS/2 1.x

F0h - OS/2 2.x

 

0012h

Width

1 dword

位图的宽度,以像素为单位

 

0016h

Height

1 dword

位图的高度,以像素为单位

 

001Ah

Planes

1 word

位图的位面数


图像

信息

 

 

001Ch

Bits Per Pixel

1 word

每个像素的位数

1 - Monochrome bitmap

4 - 16 color bitmap

8 - 256 color bitmap

16 - 16bit (high color) bitmap

24 - 24bit (true color) bitmap

32 - 32bit (true color) bitmap

 

001Eh

Compression

1 dword

压缩说明:

0 - none (也使用BI_RGB表示)

1 - RLE 8-bit / pixel (也使用BI_RLE4表示)

2 - RLE 4-bit / pixel (也使用BI_RLE8表示)

3 - Bitfields (也使用BI_BITFIELDS表示)

 

0022h

Bitmap Data Size

1 dword

用字节数表示的位图数据的大小。该数必须是4的倍数

 

0026h

HResolution

1 dword

用像素/米表示的水平分辨率

 

002Ah

VResolution

1 dword

用像素/米表示的垂直分辨率

 

002Eh

Colors

1 dword

位图使用的颜色数。如8-位/像素表示为100h或者 256.

 

0032h

Important Colors

1 dword

指定重要的颜色数。当该域的值等于颜色数时,表示所有颜色都一样重要

调色板数据

0036h

Palette

N * 4 byte

调色板规范。对于调色板中的每个表项,这4个字节用下述方法来描述RGB的值:

  • 1字节用于蓝色分量
  • 1字节用于绿色分量
  • 1字节用于红色分量
  • 1字节用于填充符(设置为0)

图像数据

0436h

Bitmap Data

x bytes

该域的大小取决于压缩方法,它包含所有的位图数据字节,这些数据实际就是彩色调色板的索引号

 

6.1.3 构件详解

1. 位图文件头

位图文件头包含有关于文件类型、文件大小、存放位置等信息,在Windows 3.0以上版本的位图文件中用BITMAPFILEHEADER结构来定义:

typedef struct tagBITMAPFILEHEADER { /* bmfh */

UINT bfType;

DWORD bfSize;

UINT bfReserved1;

UINT bfReserved2;

DWORD bfOffBits;

} BITMAPFILEHEADER;

其中:

bfType

说明文件的类型.

bfSize

说明文件的大小,用字节为单位

bfReserved1

保留,设置为0

bfReserved2

保留,设置为0

bfOffBits

说明从BITMAPFILEHEADER结构开始到实际的图像数据之间的字 节偏移量

 

2. 位图信息头

位图信息用BITMAPINFO结构来定义,它由位图信息头(bitmap-information header)和彩色表(color table)组成,前者用BITMAPINFOHEADER结构定义,后者用RGBQUAD结构定义。BITMAPINFO结构具有如下形式:

typedef struct tagBITMAPINFO { /* bmi */

BITMAPINFOHEADER bmiHeader;

RGBQUAD bmiColors[1];

} BITMAPINFO;

其中:

bmiHeader

说明BITMAPINFOHEADER结构

bmiColors

说明彩色表RGBQUAD结构的阵列

BITMAPINFOHEADER结构包含有位图文件的大小、压缩类型和颜色格式,其结构定义为:

typedef struct tagBITMAPINFOHEADER { /* bmih */

DWORD biSize;

LONG biWidth;

LONG biHeight;

WORD biPlanes;

WORD biBitCount;

DWORD biCompression;

DWORD biSizeImage;

LONG biXPelsPerMeter;

LONG biYPelsPerMeter;

DWORD biClrUsed;

DWORD biClrImportant;

} BITMAPINFOHEADER;

其中:

biSize

说明BITMAPINFOHEADER结构所需要的字节数

biWidth

说明图像的宽度,以像素为单位

biHeight

说明图像的高度,以像素为单位

biPlanes

为目标设备说明位面数,其值设置为1

biBitCount

说明位数/像素,其值为1、2、4或者24

biCompression

  • 说明图像数据压缩的类型。其值可以是下述值之一:
    BI_RGB:没有压缩;
  • BI_RLE8:每个像素8位的RLE压缩编码,压缩格式由2字节组成(重复像素计数和颜色索引);
  • BI_RLE4:每个像素4位的RLE压缩编码,压缩格式由2字节组成

biSizeImage

说明图像的大小,以字节为单位。当用BI_RGB格式时,可设置为0

biXPelsPerMeter

说明水平分辨率,用像素/米表示

biYPelsPerMeter

说明垂直分辨率,用像素/米表示

biClrUsed

说明位图实际使用的彩色表中的颜色索引数

biClrImportant

说明对图像显示有重要影响的颜色索引的数目,如果是0,表示都重要。

现就BITMAPINFOHEADER结构作如下说明:

(1) 彩色表的定位

应用程序可使用存储在biSize成员中的信息来查找在BITMAPINFO结构中的彩色表,如下所示:

pColor = ((LPSTR) pBitmapInfo + (WORD) (pBitmapInfo->bmiHeader.biSize))

(2) biBitCount

biBitCount=1 表示位图最多有两种颜色,黑色和白色。图像数据阵列中的每一位表示一个像素。

biBitCount=4 表示位图最多有16种颜色。每个像素用4位表示,并用这4位作为彩色表的表项来查找该像素的颜色。例如,如果位图中的第一个字节为0x1F,它表示有两个像素,第一像素的颜色就在彩色表的第2表项中查找,而第二个像素的颜色就在彩色表的第16表项中查找。

biBitCount=8 表示位图最多有256种颜色。每个像素用8位表示,并用这8位作为彩色表的表项来查找该像素的颜色。例如,如果位图中的第一个字节为0x1F,这个像素的颜色就在彩色表的第32表项中查找。

biBitCount=24 表示位图最多有224=16 777 216种颜色。bmiColors (或者bmciColors)成员就为NULL。每3个字节代表一个像素,其颜色有R、G、B字节的相对强度决定。

(3) ClrUsed

BITMAPINFOHEADER结构中的成员ClrUsed指定实际使用的颜色数目。如果ClrUsed设置成0,位图使用的颜色数目就等于biBitCount成员中的数目。

(4) 图像数据压缩

① BI_RLE8:每个像素为8位的RLE压缩编码,可使用编码方式和绝对方式中的任何一种进行压缩,这两种方式可在同一幅图中的任何地方使用。

编码方式:由2个字节组成,第一个字节指定使用相同颜色的像素数目,第二个字节指定使用的颜色索引。此外,这个字节对中的第一个字节可设置为0,联合使用第二个字节的值表示:

  • 第二个字节的值为0:行的结束。
  • 第二个字节的值为1:图像结束。
  • 第二个字节的值为2:其后的两个字节表示下一个像素从当前开始的水平和垂直位置的偏移量。

绝对方式:第一个字节设置为0,而第二个字节设置为0x03~0xFF之间的一个值。在这种方式中,第二个字节表示跟在这个字节后面的字节数,每个字节包含单个像素的颜色索引。压缩数据格式需要字边界(word boundary)对齐。

[例6.1] 用十六进制表示的8位压缩图像数据如下:

03 04 05 06 00 03 45 56 67 00 02 78 00 02 05 01 02 78 00 00 09 1E 00 01
这些压缩数据可解释为 :

压缩数据

扩展数据

03 04

04 04 04

05 06

06 06 06 06 06

00 03 45 56 67 00

45 56 67

02 78

78 78

00 02 05 01

从当前位置右移5个位置后向下移一行

02 78

78 78

00 00

行结束

09 1E

1E 1E 1E 1E 1E 1E 1E 1E 1E

00 01

RLE编码图像结束

② BI_RLE4:每个像素为4位的RLE压缩编码,同样也可使用编码方式和绝对方式中的任何一种进行压缩,这两种方式也可在同一幅图中的任何地方使用。这两种方式是:

编码方式:由2个字节组成,第一个字节指定像素数目,第二个字节包含两种颜色索引,一个在高4位,另一个在低4位。第一个像素使用高4位的颜色索引,第二个使用低4位的颜色索引,第3个使用高4位的颜色索引,依此类推。

绝对方式:这个字节对中的第一个字节设置为0,第二个字节包含有颜色索引数,其后续字节包含有颜色索引,颜色索引存放在该字节的高、低4位中,一个颜色索引对应一个像素。此外,BI_RLE4也同样联合使用第二个字节中的值表示:

  • 第二个字节的值为0:行的结束。
  • 第二个字节的值为1:图像结束。
  • 第二个字节的值为2:其后的两个字节表示下一个像素从当前开始的水平和垂直位置的偏移量。

[例6.2] 用十六进制数表示的4位压缩图像数据:

03 04 05 06 00 06 45 56 67 00 04 78 00 02 05 01 04 78 00 00 09 1E 00 01

这些压缩数据可解释为 :

压缩数据

扩展数据

03 04

0 4 0

05 06

0 6 0 6 0

00 06 45 56 67 00

4 5 5 6 6 7

04 78

7 8 7 8

00 02 05 01

从当前位置右移5个位置后向下移一行

04 78

7 8 7 8

00 00

行结束

09 1E

1 E 1 E 1 E 1 E 1

00 01

RLE图像结束

 

3. 彩色表

彩色表包含的元素与位图所具有的颜色数相同,像素的颜色用RGBQUAD结构来定义。对于24-位真彩色图像就不使用彩色表,因为位图中的RGB值就代表了每个像素的颜色。彩色表中的颜色按颜色的重要性排序,这可以辅助显示驱动程序为不能显示足够多颜色数的显示设备显示彩色图像。RGBQUAD结构描述由R、G、B相对强度组成的颜色,定义如下:

typedef struct tagRGBQUAD { /* rgbq */

BYTE rgbBlue;

BYTE rgbGreen;

BYTE rgbRed;

BYTE rgbReserved;

} RGBQUAD;

其中:

rgbBlue

指定蓝色强度

rgbGreen

指定绿色强度

rgbRed

指定红色强度

rgbReserved

保留,设置为0

 

4. 位图数据

紧跟在彩色表之后的是图像数据字节阵列。图像的每一扫描行由表示图像像素的连续的字节组成,每一行的字节数取决于图像的颜色数目和用像素表示的图像宽度。扫描行是由底向上存储的,这就是说,阵列中的第一个字节表示位图左下角的像素,而最后一个字节表示位图右上角的像素。



Exif文件格式描述

当前,几乎新型的数码相机都使用Exif文件格式来存储图像. 它的规格是由  JEIDA  来制定的, 但是在互联网上还没有开放的文档可供浏览. 因此我根据从互联网上所能得到一些开放资料做成了这份Exif格式的描述文档.

注: 现在我们能得到官方的文档 Exif2.1 ,它来自 PIMA 的web站点.

ISO 正致力于建立 DCF (Design rule for Camera File system/相机文件系统设计规则) 规格. 所有的数码相机的制造商正准备遵循这份规则并且已经在他们的最新的数字相机上使用了. DCF规格为数字相机定义了完整的文件系统; 如,目录结构, 文件命名方法, 字符集和文件格式等等. 这里的文件格式就是基于 Exif2.1 规格制定的.

这份文档基本上是基于 Exif2.1/DCF 规格做成的, 如果你有关于 'unknown' 条目的信息或者是发现了勘误, 请 e-mail 我, TsuruZoh Tachibanaya ,  t s u r u z o h @ b a . w a k w a k . c o m 


这是一份免费的文档, 你可以使用于任何目的(商业/非商业)下. 文档里面提到的所有的商业名称都是商标或者被各自持有者所注册的商标. 

TsuruZoh Tachibanaya, t s u r u z o h @ b a . w a k w a k . c o m 

http://park2.wakwak.com/~tsuruzoh/

rev. 1.4 Feb.03,2001
rev. 1.3 Sep.09,2000
rev. 1.2 Jul.19,2000
rev. 1.1 Dec.19,1999
rev. 1.0 May.28,1999


参考材料

Exif文件格式 itojun著 (日文版文档)
Exif文件格式 Mamoru Ohno著 (日文版文档)
TIFF6.0 规格说明 Adobe公司著
TIFF/EP 规格说明 ISO TC42 WG18著
exifdump 程序由 Thierry Boush完成制作
DCF 规格说明 ISO TC42 WG18著
Exif2.1 规格说明  JEIDA




什么是 Exif?

基本上, Exif文件格式与JPEG 文件格式相同. Exif按照JPEG的规格在JPEG中插入一些 图像/数字相机 的信息数据以及缩略图像. 于是你能通过与JPEG兼容的互联网浏览器/图片浏览器/图像处理等一些软件 来查看Exif格式的图像文件. 就跟浏览通常的JPEG图像文件一样.

JPEG格式和标记

每一个JPEG文件的内容都开始于一个二进制的值 '0xFFD8', 并结束与二进制值'0xFFD9'. 在JPEG的数据 中有好几种类似于二进制 0xFFXX 的数据, 它们都统称作  "标记" , 并且它们代表了一段JPEG的 信息数据. 0xFFD8 的意思是  SOI 图像起始(Start of image), 0xFFD9 则表示  EOI 图像结束 (End of image). 这两个特殊的标记的后面都不跟随数据, 而其他的标记在后面则会附带数据. 标记的基本 格式如下.

0xFF+标记号(1个字节)+数据大小描述符(2个字节)+数据内容(n个字节)

数据大小描述符
(2个字节) 是 "Motorola" 的字节顺序, 数据的低位被存放在高地址,也就是 BigEndian. 请注意上面中的 "数据内容" 中包含他前面的数据大小描述符, 如果下面的是一个标记的话;

FF C1 00 0C

它就表示这个标记(0xFFC1) 的数据占 0x000C(等于12)个字节. 但是这个数据大小'12' 包含了 "数据大小" 描述符, 也就是在0x000C后面它只允许带有10 个字节大小的数据.

在JPEG 格式中, 最开始先是用一些标记来描述数据, 然后是放置  SOS 数据流的起始(Start of stream) 标记. 在SOS标记的后面才是, 存放JPEG图像的数据流并终结于EOI标记.

SOI 标记标记 XX 的大小=SSSS标记 YY 的大小=TTTTSOS 标记 的大小=UUUU图像数据流EOI 标记
FFD8FFXXSSSSDDDD......FFYYTTTTDDDD......FFDAUUUUDDDD....I I I I....FFD9

Exif使用的标记

0xFFE0~0xFFEF之间的标记被叫做  "应用标记" , 它们在JPEG图像解码中不是必须存在的. 它们被使用于用户的应用程序之中. 例如, 老款的olympus/canon/casio/agfa 数字相机使用 JFIF(JPEG文件交换格式/JPEG File Interchange Format)来存储图像. JFIF 使用 APP0(0xFFE0) 标记来插入数字相机的配置信息数据和缩略图.

Exif也使用应用标记来插入数据, 但是Exif 使用  APP1(0xFFE1) 标记来避免与JFIF格式的 冲突. 且每一个 Exif 文件格式都开始于它, 如;

SOI 标记APP1 标记APP1 数据Other 标记
FFD8FFE1SSSS 457869660000 TTTT......FFXX SSSS DDDD......

该图像文件从SOI(0xFFD8) 标记开始, 因此它是一个 JPEG 文件. 后面马上跟着 APP1 标记. 而它的所有 Exif数据都被存储在 APP1 数据域中. 上面的 "SSSS" 这部分表示 APP1 数据域 (Exif data area)的大小. 请注意这里的大小 "SSSS" 包含描述符本身的大小. 

在 "SSSS"后面, 是 APP1 的数据. 其中第一个部分是一个特殊的数据,它用来标识是否是 Exif, 其值是ASCII 字符 "Exif" 和 两个0x00字节 的组合字符串.

在 APP1 标记域的后面是, 跟随着其他的 JPEG 标记. 

Exif数据结构

Exif的数据结构 (APP1)大致如下面那样. 这是"Intel"字节序的情况, 并且它包含了JPEG 格式的 缩略图. 就像上面描述的那样, Exif 数据开始于ASCII字符 "Exif" 和2个字节的0x00, 后面才是 Exif的数据. Exif 使用 TIFF 格式来存储数据. 想获取TIFF的更多的细节的话, 请参考  "TIFF6.0规格说明(TIFF6.0 specification)" .


FFE1APP1 标记
SSSSAPP1 数据APP1 数据大小
45786966 0000Exif 头
49492A00 08000000TIFF 头
XXXX. . . .IFD0 (主图像)目录
LLLLLLLL连接到 IFD1
XXXX. . . .IFD0的数据域
XXXX. . . . Exif 子IFD目录
00000000连接结束
XXXX. . . .Exif 子IFD的数据域
XXXX. . . . Interoperability IFDDirectory
00000000连接结束
XXXX. . . .Interoperability IFD的数据域
XXXX. . . .Makernote IFDDirectory
00000000连接结束
XXXX. . . .Makernote IFD的数据域
XXXX. . . .IFD1(缩略图像)目录
00000000连接结束
XXXX. . . .IFD1的数据域
FFD8XXXX. . . XXXXFFD9缩略图像

TIFF 头的结构

TIFF格式中前8个字节是 TIFF 头. 其中最开始的前2个字节定义了 TIFF 数据的字节序. 如果这个值是 0x4949="I I"的话, 就表示按照 "Intel" 的字节序(Little Endian) 来排列数据. 如果是 0x4d4d="MM", 则说明按照 "Motorola" 的字节序(Big Endian)来排列数据. 例如, 这个值是'305,419,896' (注意:16进制值为0x12345678). 在 Motorola 的 字节序中, 数据存储时的排列顺序为 0x12,0x34,0x56,0x78. 而用 Intel 的字节序的话, 它就是按照 0x78,0x56,0x34,0x12 来排序数据. 几乎所有的数字相机都是使用 Intel 的字节序. 不过 Ricoh 使用的是 Motorola 的. Sony 使用的是 Intel 字节序(除了 D700). Kodak 的DC200/210/240 使用的是 Motorola 字节序, 但是 DC220/260 使用的是 Intel的, 尽管它们都是使用在 PowerPC的平台上! 因此当我们需要使用 Exif 数据的值的时候, 我们必须每次都要检查它的字节序. 尽管 JPEG 数据仅仅是使用 Motorola 字节序, 但 Exif 却是允许这两种字节序存在的. 我不明白 Exif 为什么不把字节序修订成 Motorola的. 

随后的两个字节是一个2字节长度的固定值 0x002A. 如果数据使用 Intel 字节序, 则这两个 字节的数据排列为 "0x2a,0x00". 如果是 Motorola 的, 则是 "0x00,0x2a". TIFF头的最后的 4个字节是到第一个 IFD(图像文件目录/Image File Directory, 将在下一节中描述)的偏移量. 这个偏移量是指从TIFF头("II" 或者 "MM")开始, 包含自己偏移量值的本身, 到下一个IFD为止的 长度的字节数. 通常地第一个 IFD 是紧挨着 TIFF 头出现的, 因此这个偏移量的值是 '0x00000008'.

字节序标签标注到第一个IFD的偏移量
"I I" or "MM"0x002a0x00000008

IFD : 图像文件目录

紧挨着 TIFF 头, 就是第一个 IFD:图像文件目录(Image File Directory). 它包含了图像 信息的数据. 在下面的表格中, 前两个字节('EEEE') 表示在IFD中有多少个目录项(directory entry) . 它后面存放就是目录项(每个项目大小为12字节) . 在最后一个目录项之后, 有 一个4个字节大小的数据(表格中'LLLLLLLL' ), 它意味着到下一个IFD的偏移量. 如果这个 值是'0x00000000', 则表示它是最后一个IFD 并且不在跟任何的 IFD 相连接.

EEEE目录项的号码
TTTTffffNNNNNNNNDDDDDDDD项目 0
TTTTffffNNNNNNNNDDDDDDDD项目 1
. . . . . . . . .. . . . . .
TTTTffffNNNNNNNNDDDDDDDD项目 EEEE-1
LLLLLLLL到下一个IFD的偏移量

上表中的'TTTT'(2个字节) 是一个标签的号码, 代表数据的种类. 'ffff'(2个字节)表示 数据的格式, 'NNNNNNNN'(4个字节)表示组件的数目. 'DDDDDDDD'(4个字节) 则是数据的 值或者到数据值的偏移量.

数据格式

数据格式 (上面表格中的'ffff') 的定义如下表示. "rational" 的意思是说明数据的 内容是一个分数, 它含有2个有符号/无符号的长整形(signed/unsigned long integer)值, 并且第一个值表示的是分子, 第二个值则是, 分母. 
数据的值123456
格式unsigned byteascii stringsunsigned shortunsigned longunsigned rationalsigned byte
组件的大小(字节数)112481
 
数据的值789101112
格式undefinedsigned shortsigned longsigned rationalsingle floatdouble float
组件的大小(字节数)124848

通过多个存储在'NNNNNNNN'数据区的'组件的大小(字节数)'你能得到所有数据的字节长度. 如果数据的长度小于4个字节, 则'DDDDDDDD' 就表示的是标签的值. 如果长度超过4字节, 则'DDDDDDDD' 里存放的就是所要存储数据的偏移量地址. 

IFD数据结构

在Exif格式中, 第一个IFD 是IFD0(主图像IFD), 然后它连接到IFD1(缩略图IFD) 并且IFD 连接在此结束. 但是 IFD0/IFD1 不包含任何的数字相机的信息例如快门速度, 焦距等. IFD0 总是包含一个特殊的标签  Exif偏移量(0x8769) , 它表示到  Exif子IFD  的偏移量. Exif子IFD 也是一个IFD 格式化的数据, 它包含了数字相机的信息.

在扩展Exif格式(Exif2.1/DCF)中, Exif子IFD还包含了特殊的标签  Exif Interoperability Offset (0xa005) . 这个偏移量也指向Interoperability IFD. 根据 DCF 规格, 这个标签是必须的并且子IFD (主图像 IFD) 和 IFD1 (缩略图 IFD) 中可能也会包含Interoperability IFD. 通常, 仅仅主图像仅仅有这个标签.

另外一些数字相机也为Makernote(制造商注释)使用 IFD 数据格式; 这是生产商特定的 魔数(magic number)区域. 判断makernote 是否是IFD 格式是非常困难的, 必须仔细的 编程. 关于Makernote的信息请参考附录. 
0000: 49 49 2A 00 08 00 00 00-02 00 1A 01 05 00 01 00
0010: 00 00 26 00 00 00 69 87-04 00 01 00 00 00 11 02
0020: 00 00 40 00 00 00 48 00-00 00 01 00 00 00
上面的是TIFF数据的开头部分, 对它的解读如下;
  • 前两个字节是 "I I", 所以字节序是 'Intel'.
  • 在地址0x0004~0x0007处存放的值是 0x08000000, 因此IFD0 从地址 '0x0008'开始
  • 在地址0x0008~0x0009处存放的值是 0x0200, 则表示IFD0有 '2' 个目录项.
  • 在地址0x000a~0x000b处存放的值是 0x1A01, 它意味着这是一个 XResolution(0x011A) 标签, 表示这是图像的水平分辨率.
  • 地址0x000c~0x000d处存放的值为 0x0500, 说明数据的格式是一个 unsigned rational(0x0005).
  • 地址0x000e~0x0011处存放的值是 0x01000000, 说明组件的数据只有 '1'个. Unsigned rational的数据大小是8字节(组件的大小), 因此数据的总长度是 1x8=8字节.
  • 总数居长度比4字节大了, 因此它后面的4个字节里面存放的是一个指向实际数据的偏移量地址.
  • 地址0x0012~0x0015处存放的是 0x26000000, 表示XResolution(水平分辨率) 数据的存储地址是0x0026
  • 地址0x0026~0x0029处存放的数据是 0x48000000, 说明分子的值为 72, 而地址0x002a~0x002d 处存放的是0x0100000000, 说明分母为 '1'. 因此XResoultion 的值是 72/1.
  • 地址0x0016~0x0017处存放的数据为0x6987, 表示下一个标签是 ExifOffset(0x8769). 这就是 指向 Exif子IFD的偏移量
  • 而它的数据格式是 0x0004, 即是一个无符号的长整形(unsigned long integer).
  • 这个标签只有一个组件. 无符号长整形的数据大小是4字节, 因此总数据长度为4字节.
  • 总数据长度是 4字节, 则说明下一个4字节的数据中存放的是Exif子IFD的偏移量.
  • 地址0x001e~0x0021处存放的是 0x11020000, 则说明Exif子IFD的开始地址是 '0x0211'.
  • 这是最后一个目录项, 接下来的4个字节存放的是下一个IFD的偏移地址.
  • 地址0x0022~0x0025处存放的是 0x40000000, 就可以知道下一个IFD的开始地址为 '0x0040'

缩略图

Exif格式中包含缩略图像(除了Ricoh RDC-300Z). 通常它被放到IFD1的后面. 缩略图有 3 种格式; JPEG 格式(JPEG 使用YCbCr), RGB TIFF 格式, YCbCr TIFF 格式. 在Exif2.1之后推荐使用JPEG 格式和160x120像素的尺寸. 根据 DCF 规格, 缩略图像 必须  使用JPEG 格式以及图像的尺寸 固定为160x120 像素.

JPEG格式的缩略图
IFD1中的标签 Compression(0x0103) 如果是 '6', 则缩略图就是JPEG格式. 几乎所有的 Exif图像中缩略图都使用JPEG 格式. 在这种情况下, 你能从IFD1的 JpegIFOffset(0x0201)  标签中得到缩略图的偏移量, 从标签 JpegIFByteCount(0x0202) 中得到缩略图的大小. 数据格式则是普通的 JPEG 格式, 也就是从0xFFD8处开始在0xFFD9处结束. 

TIFF格式的缩略图
IFD1的标签 Compression(0x0103) 如果是 '1', 则缩略图的格式就没有经过压缩的 (就是TIFF 图像). 缩略图数据的开始点是标签  StripOffset(0x0111)  , 缩略图的尺寸 就是标签  StripByteCounts(0x0117)  之和.

如果缩略图使用非压缩格式并且IFD1中的标签  PhotometricInterpretation(0x0106)  是 '2', 则缩略图使用了 RGB 格式. 在这种情况下, 你只要简单的把数据拷贝到计算机的RGB格式 中就能看到缩略图了(如 BMP 格式, 或者拷贝到 VRAM 目录下). Kodak DC-210/220/260 就使用 这个格式. 注意TIFF中存储的像素数据是'RGB' 顺序的, 而 BMP 里的存储顺序则是 'BGR' .
如果这个标签的值是 '6', 缩略图使用 YCbCr 格式. 如果你想要看到缩略图的话, 你必须把它 转换成 RGB 格式的. Ricoh RDC4200/4300, Fuji DS-7/300 和 DX-5/7/9 使用的是这种格式 (较新的 RDC5000/MX-X00 系列使用的是 JPEG). 在下一节中主要描述的就是Fuji DS相机的缩略图 的图像转换. 想要了解更多的信息, 请参考  TIFF6.0 规格说明 .

在DX-5/7/9的场合, YCbCrSubsampling(0x0212) 的值是 '2,1', PlanarConfiguration(0x011c) 的 值是 '1'. 因此这种图像的数据排列是下面的那样.

Y(0,0),Y(1,0),Cb(0,0),Cr(0,0), Y(2,0),Y(3,0),Cb(2,0),Cr(3.0), Y(4,0),Y(5,0),Cb(4,0),Cr(4,0). . . .

括号中的数字代表的是像素坐标. DX 系列中000YCbCrCoefficients(0x0211) 的值是 '0.299/0.587/0.114', ReferenceBlackWhite(0x0214) 的值是 '0,255,128,255,128,255'. 于是把 Y/Cb/Cr 转换成 RGB 就是;

B(0,0)=(Cb-128)*(2-0.114*2)+Y(0,0)
R(0,0)=(Cr-128)*(2-0.299*2)+Y(0,0)
G(0,0)=(Y(0,0)-0.114*B(0,0)-0.299*R(0,0))/0.587

水平 subsampling 的值是 '2', 因此你能使用 Y(1,0)和 Cr(0,0)/Cb(0,0)计算出B(1,0)/R(1,0)/G(1,0). 根据ImageWidth(0x0100) 和 ImageLength(0x0101)的值可以重复这些转换.

Exif/TIFF使用的标签数

下面显示了 Exif/TIFF 使用的标签数. 如果这个标签组件数目的上限, CompoNo 一栏就代表这一数值. 如果这个数值没有, 则说明这儿没有上限值.

IFD0 (主图像)使用的标签
标签号标签名格式组件数描述
0x010eImageDescriptionascii string 用来描述图像. 双字节的字符码不能使用, 如 中文/韩文/日文.
0x010fMakeascii string 表示数字相机的制造商. 在 Exif 标准中, 这个标签是可选的, 但是在DCF中它是必需的.
0x0110Modelascii string 表示数字相机的模块代码. 在 Exif 标准中, 这个标签是可选的, 但在DCF中它也是必需的.
0x0112Orientationunsigned short1
Value0th Row0th Column
1topleft side
2topright side
3bottomright side
4bottomleft side
5left sidetop
6right sidetop
7right sidebottom
8left sidebottom
当拍照时, 相机相对于场景的方向. 在右边表示的是'0th row' 以及 '0th column' 在视觉位置上的关系.
0x011aXResolutionunsigned rational1图像的 显示/打印 分辨率. 缺省值是 1/72英寸, 但是它没有意义因为个人PC在 显示/打印 图像的时候不使用这个值.
0x011bYResolutionunsigned rational1
0x0128ResolutionUnitunsigned short1XResolution(0x011a)/YResolution(0x011b)的单位. '1' 表示没有单位, '2' 意味着英寸, '3' 表示厘米. 缺省值是 '2'(英寸).
0x0131Softwareascii string 显示固件的版本号(数字相机的内部控制软件).
0x0132DateTimeascii string20图像最后一次被修改时的日期/时间. 日期的格式是 "YYYY:MM:DD HH:MM:SS"+0x00, 一共 20个字节. 如果没有设置时钟或者数字相机没有时钟, 则这个域是用空格来填充. 通常, 它和DateTimeOriginal(0x9003)具有相同的值
0x013eWhitePointunsigned rational2定义图像白点(white point/白点:在彩色分色、照相或摄影时作为色彩平衡测量用途的参考点) 的色度(chromaticity). 如果图像是用CIE标准照度 D65(著名的是 '光线/daylight'的国际标准), 这个值是 '3127/10000,3290/10000'.
0x013fPrimaryChromaticitiesunsigned rational6定义图像的原始色度. 如果图像使用 CCIR 推荐 709原始色度, 则这个值是 '640/1000,330/1000,300/1000,600/1000,150/1000,0/1000'.
0x0211YCbCrCoefficientsunsigned rational3当图像的格式是 YCbCr(JPEG的格式), 这个值表示转换成 RGB格式的一个常量. 通常, 这个值是'0.299/0.587/0.114'.
0x0213YCbCrPositioningunsigned short1当图像的格式是 YCbCr 并且使用 '子采样/Subsampling'(色度数据的剪切值, 所有的数字相机都使用), 定义了subsampling 像素阵列的色度采样点. '1'表示像素阵列的中心, '2' 表示基准点.
0x0214ReferenceBlackWhiteunsigned rational6表示黑点(black point)/白点 的参考值. 在YCbCr 格式中,前两个值是 Y的黑点/白点, 下两个值是 Cb, 最后两个值是 Cr. 而在 RGB 格式中, 前两个表示R的黑点/白点, 下两个是 G, 最后两个是 B.
0x8298Copyrightascii string 表示版权信息
0x8769ExifOffsetunsigned long1Exif 子IFD的偏移量


Exif 子IFD使用的标签
标签号标签名格式组件数描述
0x829aExposureTimeunsigned rational1曝光时间 (快门速度的倒数). 单位是秒.
0x829dFNumberunsigned rational1拍照时的光圈F-number(F-stop).
0x8822ExposureProgramunsigned short1拍照时相机使用的曝光程序. '1' 表示手动曝光, '2' 表示正常程序曝光, '3' 表示光圈优先曝光, '4' 表示快门优先曝光, '5' 表示创意程序(慢速程序), '6' 表示动作程序(高速程序), '7'表示 肖像模式, '8' 表示风景模式.
0x8827ISOSpeedRatingsunsigned short2CCD 的感光度, 等效于 Ag-Hr 胶片的速率.
0x9000ExifVersionundefined4Exif 的版本号. 用4个ASCII字符来存储. 如果图片是基于Exif V2.1的, 这个值是 "0210". 因为它不是一个用NULL(0x00)来终结的字符串,所以这里的类型是 'undefined'.
0x9003DateTimeOriginalascii string20照片在被拍下来的日期/时间. 使用用户的软件是不能被修改这个值的. 日期的格式是 "YYYY:MM:DD HH:MM:SS"+0x00, 一共占用20个字节. 如果数字相机没有设置时钟或者 数字相机没有时钟, 这个域使用空格来填充. 在Exif标准中, 这个标签是可选的, 但是在 DCF中是必需的.
0x9004DateTimeDigitizedascii string20照片被数字化时的日期/时间. 通常, 它与DateTimeOriginal(0x9003)具有相同的值. 数据格式是 "YYYY:MM:DD HH:MM:SS"+0x00, 一共占用20个字节. 如果数字相机没有设置时钟或者 数字相机没有时钟, 这个域使用空格来填充. 在Exif标准中, 这个标签是可选的, 但是在 DCF中是必需的.
0x9101ComponentsConfigurationundefined 表示的是像素数据的顺序. 大多数情况下RGB格式使用 '0x04,0x05,0x06,0x00' 而YCbCr 格式使用 '0x01,0x02,0x03,0x00'. 0x00:并不存在, 其他的对应关系为 0x01:Y, 0x02:Cb, 0x03:Cr, 0x04:Red, 0x05:Green, 0x06:Bllue.
0x9102CompressedBitsPerPixelunsigned rational1JPEG (粗略的估计)的平均压缩率.
0x9201ShutterSpeedValuesigned rational1用APEX表示出的快门速度. 为了转换成原始的 'Shutter Speed'; 则先要计算2的ShutterSpeedValue次幂, 然后求倒数. 例如, 如果 ShutterSpeedValue 是 '4', 快门速度则是1/(24)=1/16秒.
0x9202ApertureValueunsigned rational1拍照时镜头的光圈. 单位是 APEX. 为了转换成普通的 F-number(F-stop), 则要先计算出根号2 2 (=1.4142)的ApertureValue次幂. 例如, 如果ApertureValue 是 '5', F-number 就等于1.41425 = F5.6.
0x9203BrightnessValuesigned rational1被拍摄对象的明度, 单位是 APEX. 为了从BrigtnessValue(Bv)计算出曝光量(Ev), 你必须加上 SensitivityValue(Sv).
Ev=Bv+Sv   Sv=log2(ISOSpeedRating/3.125)
ISO100:Sv=5, ISO200:Sv=6, ISO400:Sv=7, ISO125:Sv=5.32.
0x9204ExposureBiasValuesigned rational1照片拍摄时的曝光补偿. 单位是APEX(EV).
0x9205MaxApertureValueunsigned rational1镜头的最大光圈值. 你可以通过计算根号2的MaxApertureValue次幂来转换成普通的光圈 F-number (跟ApertureValue:0x9202的处理过程一样).
0x9206SubjectDistancesigned rational1到焦点的距离, 单位是米.
0x9207MeteringModeunsigned short1曝光的测光方法. '0' 表示未知, '1' 为平均测光, '2' 为中央重点测光, '3' 是点测光, '4' 是多点测光, '5' 是多区域测光, '6' 部分测光, '255' 则是其他.
0x9208LightSourceunsigned short1光源, 实际上是表示白平衡设置. '0' 意味着未知, '1'是日光, '2'是荧光灯, '3' 白炽灯(钨丝), '10' 闪光灯, '17' 标准光A, '18' 标准光B, '19' 标准光C, '20' D55, '21' D65, '22' D75, '255' 为其他.
0x9209Flashunsigned short1'0' 表示闪光灯没有闪光, '1' 表示闪光灯闪光, '5' 表示闪光但没有检测反射光, '7' 表示闪光且检测了反射光.
0x920aFocalLengthunsigned rational1拍摄照片时的镜头的焦距长度. 单位是毫米.
0x927cMakerNoteundefined 制造商的内部数据. 一些制造商如 Olympus/Nikon/Sanyo 等在这个区域中使用IFD 格式的数据.
0x9286UserCommentundefined 存储用户的注释. 这个标签允许使用两字节的德字符或者 unicode. 前8 个字节描述的是字符集. 'JIS' 是日文 (著名的有 Kanji).
'0x41,0x53,0x43,0x49,0x49,0x00,0x00,0x00':ASCII
'0x4a,0x49,0x53,0x00,0x00,0x00,0x00,0x00':JIS
'0x55,0x4e,0x49,0x43,0x4f,0x44,0x45,0x00':Unicode
'0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00':Undefined
0x9290SubsecTimeascii string 一些数字相机每秒能拍摄 2~30 张照片, 但是DateTime/DateTimeOriginal/DateTimeDigitized 标签只能记录到秒单位的时间. SubsecTime 标签就是用来记录秒后面的数据(微秒).
例如, DateTimeOriginal = "1996:09:01 09:15:30", SubSecTimeOriginal = "130", 合并起来的原始的拍摄 时间就是 "1996:09:01 09:15:30.130"
0x9291SubsecTimeOriginalascii string 
0x9292SubsecTimeDigitizedascii string 
0xa000FlashPixVersionundefined4存储FlashPix 的版本信息. 如果图像数据是基于 FlashPix formar Ver.1.0, 则这个值为 "0100". 因为它不是一个用NULL(0x00)来终结的字符串,所以这里的类型是 'undefined'.
0xa001ColorSpaceunsigned short1定义色彩空间. DCF 图像必须使用 sRGB 色彩空间因此这个值总是 '1'. 如果这个照片使用了 其他的色彩空间, 这个值是 '65535':未校准(Uncalibrated).
0xa002ExifImageWidthunsigned short/long1主图像的尺寸大小.
0xa003ExifImageHeightunsigned short/long1
0xa004RelatedSoundFileascii string 如果数字相机能够纪录图像的音频数据, 则表示音频数据的名字.
0xa005ExifInteroperabilityOffsetunsigned long1表示这是一个扩展"ExifR98", 细节未知. 这个值经常是IFD格式的数据. 当前这儿有两个 目录项, 第一个是 Tag0x0001, 值是"R98", 下一个是 Tag0x0002, 它的值为 "0100".
0xa20eFocalPlaneXResolutionunsigned rational1表示CCD的像素密度. 如果你的相机是百万像素的并且是用低分辨率(如VGA模式) 来拍摄照片, 这个值可以通过照片的分辨率来重新采样. 在这种情况下, FocalPlaneResolution 就不是CCD的实际的分辨率.
0xa20fFocalPlaneYResolutionunsigned rational1
0xa210FocalPlaneResolutionUnitunsigned short1FocalPlaneXResoluton/FocalPlaneYResolution的单位. '1' 表示没有单位, '2'是英寸inch, '3' 表示厘米. 

注意:一些Fujifilm的数码相机(如.FX2700,FX2900,Finepix4700Z/40i 等) 使用的值是 '3' 所以它的单位一定是 '厘米' , 但是它们的分辨率单位就变成'8.3mm?'(1/3in.?). 这是Fuji 的 BUG? 从Finepix4900Z 开始这个值就使用 '2' 了但仍然跟实际的值不吻合.
0xa215ExposureIndexunsigned rational1跟ISOSpeedRatings(0x8827)一样但是数据类型是 unsigned rational. 只有Kodak的数字相机使用 这个标签来替代 ISOSpeedRating, 我不知道这是为什么(历史原因?).
0xa217SensingMethodunsigned short1表示图像传感器单元的类型. '2' 意味着这是一个芯片颜色区域传感器, 几乎所有的数字相机都 使用这个类型.
0xa300FileSourceundefined1显示图像来源. 值 '0x03' 表示图像源是数字定格相机.
0xa301SceneTypeundefined1表示拍摄场景的类型. 值 '0x01' 表示图像是通过相机直接拍摄出来的.
0xa302CFAPatternundefined 表示色彩过滤阵列(CFA) 几何模式.
长度类型意义
2shortHorizontal repeat pixel unit = n
2shortVertical repeat pixel unit = m
1byteCFA value[0,0]
:
:
:
1byteCFA value[n-1,0]
1byteCFA value[0,1]
:
:
:
1byteCFA value[n-1,m-1]

色彩过滤和CFA值之间的关系.
Filter ColorRedGreenBlueCyanMagentaYellowWhite
CFA value0123456

RG
GB
例如, 普通的 RGB 过滤器使用左表的副本, 这个值是 '0x0002,0x0002,0x00,0x01,0x01,0x02'. 



Interoperability IFD使用的标签
标签号标签名格式组件号描述
0x0001InteroperabilityIndexAscii string4如果这个IFD 是主图像的 IFD 并且文件内容采用的是 ExifR98 v1.0, 那这个值就是 "R98". 如果是所略图的, 这个值则是 "THM".
0x0002InteroperabilityVersionUndefined4纪录interoperability的版本. "0100" 表示版本1.00.
0x1000RelatedImageFileFormatAscii stringany纪录图像文件的文件格式. 这个值是 ascii 字符串(如. "Exif JPEG Ver. 2.1").
0x1001RelatedImageWidthShort or Long1纪录图像的大小尺寸.
0x1001RelatedImageLengthShort or Long1



IFD1 (缩略图)使用的标签
标签号标签名格式组件数描述
0x0100ImageWidthunsigned short/long1表示缩略图的大小.
0x0101ImageLengthunsigned short/long1
0x0102BitsPerSampleunsigned short3当图像格式没有经过压缩, 这个值表示每像素的比特位的数目. 通常这个值是 '8,8,8'
0x0103Compressionunsigned short1代表压缩的方式. '1' 表示非压缩, '6' 表示JPEG 压缩格式.
0x0106PhotometricInterpretationunsigned short1表示图像数据组件的色彩空间. '1' 意味着单色, '2'表示 RGB, '6' 表示 YCbCr.
0x0111StripOffsetsunsigned short/long 如果图像格式没有经过压缩, 这个值表示的是到图像数据的偏移量. 在图像数据被分割的 情况下它有多个值.
0x0115SamplesPerPixelunsigned short1如果图像格式没有经过压缩, 这个值表示每个像素中存储的组件数目. 在彩色图像中, 此值为 '3'.
0x0116RowsPerStripunsigned short/long1如果图像格式没有经过压缩 并且 图像被分割存储, 这个值表示每条数据带存储了多少行数据 . 如果图像没有被分割, 它与ImageLength(0x0101)同值.
0x0117StripByteConuntsunsigned short/long 如果图像格式没有经过压缩 并且 图像被分割存储, 这个值表示每条数据带使用了多少字节的 数据 且 有多个值. 如果图像没有被分割, 它只有一个且表示为图像的所有数据的大小.
0x011aXResolutionunsigned rational1图像的显示/打印分辨率. 很多的数字相机都使用1/72英寸的规格, 但对于个人PC 来讲这个值没有任何意义因为在显示/打印的时候不使用这个值.
0x011bYResolutionunsigned rational1
0x011cPlanarConfigurationunsigned short1如果图像格式是非压缩YCbCr的, 这个值表示YCbCr数据的字节对齐顺序. '1', 表示Y/Cb/Cr值是一个 chunky format, 对于每个子采样像素都是连续的. '2', 则表示Y/Cb/Cr 值被分割存储在 Y plane/Cb plane/Cr plane 格式中.
0x0128ResolutionUnitunsigned short1XResolution(0x011a)/YResolution(0x011b)的单位. '1' 表示英寸, '2' 表示厘米.
0x0201JpegIFOffsetunsigned long1当图像格式是JPEG时, 这个值表示到 JPEG 数据的偏移量.
0x0202JpegIFByteCountunsigned long1当图像格式是JPEG时, 表示JPEG 图像的数据大小.
0x0211YCbCrCoefficientsunsigned rational3当图像格式是YCbCr时, 它表示转换成RGB格式的一个常量值. 通常是'0.299/0.587/0.114'.
0x0212YCbCrSubSamplingunsigned short2当图像格式是YCbCr时 并且 使用子采样(色度数据的剪切值, 所有的数字相机都使用)时, 这个值表示有多少个色度数据被采样了. 首先第一个值表示水平的, 下一个值表示垂直的 采样率.
0x0213YCbCrPositioningunsigned short1当图像格式是YCbCr时 并且 使用子采样(色度数据的剪切值, 所有的数字相机都使用)时, 这个值定义了被采样的像素阵列的色度采样点. '1' 表示像素阵列的中心, '2' 表示基准点(0,0).
0x0214ReferenceBlackWhiteunsigned rational6表示黑点/白点的参考值. 在 YCbCr 格式的情况下, 前两个表示了Y的黑/白, 下两个是 Cb, 最后两个是 Cr. 在 RGB 的情况下, 前两个表示R的黑/白, 下两个是 G, 最后两个是 B.


Misc Tags
标签号标签名格式组件数描述
0x00feNewSubfileTypeunsigned long1 
0x00ffSubfileTypeunsigned short1 
0x012dTransferFunctionunsigned short3 
0x013bArtistascii string  
0x013dPredictorunsigned short1 
0x0142TileWidthunsigned short1 
0x0143TileLengthunsigned short1 
0x0144TileOffsetsunsigned long  
0x0145TileByteCountsunsigned short  
0x014aSubIFDsunsigned long  
0x015bJPEGTablesundefined  
0x828dCFARepeatPatternDimunsigned short2 
0x828eCFAPatternunsigned byte  
0x828fBatteryLevelunsigned rational1 
0x83bbIPTC/NAAunsigned long  
0x8773InterColorProfileundefined  
0x8824SpectralSensitivityascii string  
0x8825GPSInfounsigned long1 
0x8828OECFundefined  
0x8829Interlaceunsigned short1 
0x882aTimeZoneOffsetsigned short1 
0x882bSelfTimerModeunsigned short1 
0x920bFlashEnergyunsigned rational1 
0x920cSpatialFrequencyResponseundefined  
0x920dNoiseundefined  
0x9211ImageNumberunsigned long1 
0x9212SecurityClassificationascii string1 
0x9213ImageHistoryascii string  
0x9214SubjectLocationunsigned short4 
0x9215ExposureIndexunsigned rational1 
0x9216TIFF/EPStandardIDunsigned byte4 
0xa20bFlashEnergyunsigned rational1 
0xa20cSpatialFrequencyResponseunsigned short1 
0xa214SubjectLocationunsigned short1 


下面是各厂商的Makernote的规格说明,但由于下面所提及的相机太过于古老,不准备全部翻译。 

附录1: 奥林帕斯数字相机的MakerNote

下面是根据Peter Esherick解析出来的Olympus D450Z(C-920Z)的数据.

奥林帕斯的数字相机的MakerNote开始于 ASCII 字符串 "OLYMP". 数据格式跟IFD一样, 但是它是从偏移量 0x07 开始. 实际的数据结构的例子如下.
:0000: 4F 4C 59 4D 50 00 01 00-0B 00 00 02 04 00 03 00  OLYMP...........
    :0010: 00 00 0E 04 00 00 01 02-03 00 01 00 00 00 03 00  ................
    

标签号标签名格式组件数
0x0200SpecialModeUnsigned Long3表示照片的拍摄模式. 第一个值的意思是 0=正常, 1=未知, 2=快速, 3=全景. 第二个值意思是序列号, 第三个值表示全景的方向 1=从左到右, 2=从右到左, 3=从下到上, 4=从上到下.
0x0201JpegQualUnsigned Short1表示JPEG 的质量. 1=SQ,2=HQ,3=SHQ.
0x0202MacroUnsigned Short1表示是否是宏模式. 0=正常, 1=宏.
0x0203UnknownUnsigned Short1未知
0x0204DigiZoomUnsigned Rational1表示数字相机的放大率. 0=正常, 2=数字2倍变焦.
0x0205UnknownUnsigned Rational1未知
0x0206UnknownSigned Short6未知
0x0207SoftwareReleaseAscii string5表示固件版本.
0x0208PictInfoAscii string52包含 ASCII 格式的数据如 [PictureInfo]. 它跟老的奥林帕斯数码相机(没有采用Exif 数据格式, 如C1400/C820/D620/D340等)采用相同的数据格式.
0x0209CameraIDUndefined32包含CameraID 的数据, 用户可以使用客户端工具来改变它的内容
0x0f00DataDumpUnsigned Long30未知


附录2: 尼康相机的MakerNote

Nikon相机的MakerNote有两种格式. E700/E800/E900/E900S/E910/E950相机开始于 ASCII 字符串 "Nikon". 数据格式与IFD一样, 但是它从偏移地址0x08处开始. 除了开始字符串 之外这跟奥林帕斯相机的一样. 实际的数据结构的例子如下表示.
:0000: 4E 69 6B 6F 6E 00 01 00-05 00 02 00 02 00 06 00 Nikon...........
        :0010: 00 00 EC 02 00 00 03 00-03 00 01 00 00 00 06 00 ................
        

标签号.标签名格式组件数
0x0002UnknownAscii string6未知. E900/E900S/E910:"09.41", 其他的是:"08.00".
0x0003QualityUnsigned short1表示图像的质量设置. 在E900相机中, 1:VGA 基本, 2:VGA 正常, 3:VGA 好, 4:SXGA 基本, 5:SXGA 正常, 6:SXGA 好
0x0004Color ModeUnsigned short11:彩色, 2:黑白.
0x0005Image AdjustmentUnsigned short10:正常, 1:明亮+, 2:明亮-, 3:对比+, 4:对比-.
0x0006CCD SensitivityUnsigned short10:ISO80, 2:ISO160, 4:ISO320, 5:ISO100
0x0007White balanceUnsigned short10:自动, 1:预设, 2:日光, 3:荧光灯, 4:白炽灯, 5:阴天, 6:速度光(SpeedLight)
0x0008FocusUnsigned rational1如果是无穷远对焦, 此值为 '1/0'.
0x0009UnknownAscii string20未知
0x000aDigital ZoomUnsigned rational1'160/100' 表示 1.6x 数码变焦, '0/100' 表示没有采用数码变焦 (仅仅是光学变焦).
0x000bConverterUnsigned short1如果使用尼康的鱼眼镜头, 此值是 '1'.
0x0f00UnknownUnsigned long25~30未知


在E990像集中, 没有Ascii 字符串. 就想通常的 IFD (如. IFD0, SubIFD)一样, 从数据的第一个 字节开始就是IFD . Nikon D1 也使用这个格式. 实际数据结构的例子如下表示.
:0000: 10 00 01 00 07 00 04 00-00 00 00 01 00 00 02 00  ................
        :0010: 03 00 02 00 00 00 00 00-64 00 03 00 02 00 06 00  ........d.......
        

以下数据由  Max Lyons  解析.

Tag No.Tag NameFormatCompoNoValue
0x0001UnknownUndefined4Unknown. Always "0100". version?
0x0002ISO SettingUnsigned short20,100=ISO 100
0,200=ISO200
0,400=ISO400
etc.
0x0003Color ModeAscii stringvaries"COLOR", "B&W"
0x0004QualityAscii stringvaries"NORMAL", "FINE", "BASIC"
0x0005WhitebalanceAscii stringvaries"AUTO", "WHITE PRESET" etc.
0x0006Image SharpeningAscii stringvaries"AUTO", "HIGH" etc.
0x0007Focus ModeAscii stringvaries"AF-S" means Single AF, "AF-C" means Continuous AF.
0x0008Flash SettingAscii stringvaries"NORMAL", "RED-EYE" etc.
0x000aUnknownUnsigned rational1Unknown, Always '8832/1000'?
0x000fISO SelectionAscii stringvaries"MANUAL":User selected, "AUTO":Automatically selected.
0x0080Image AdjustmentAscii stringvaries"AUTO", "NORMAL", "CONTRAST(+)" etc.
0x0082AdapterAscii stringvaries"OFF", "FISHEYE 2", "WIDE ADAPTER" etc.
0x0085Manual Focus DistanceUnsigned rational1Distance in Meters if focus was manually selected, otherwise 0
0x0086Digital ZoomUnsigned rational1'100/100' means no digital zoom (optical zoom only), '140/100' means 1.4x digital zoom.
0x0088AF Focus PositionUndefined4'0,0,0,0':Center, '0,1,0,0':Top, '0,2,0,0':Bottom, '0,3,0,0':Left, '0,4,0,0':right
0x0010Data DumpUndefined174Unknown.


Appendix 3: MakerNote of Casio


Casio started to use Exif format from QV2000/QV8000. Casio's MakerNote format is the same as usual IFD (e.g. IFD0, SubIFD0). Example of actual data structure is shown below.
:0000: 00 14 00 01 00 03 00 00-00 01 00 0A 00 00 00 02 ................
            :0010: 00 03 00 00 00 01 00 03-00 00 00 03 00 03 00 00 ................
            
The data below is analyzed by  Eckhard Henkel  .

Tag No.Tag NameFormatCompoNoValue
0x0001RecordingModeUnsigned Short11:Single Shutter, 2:Panorama, 3:Night Scene, 4:Portrait, 5:Landscape
0x0002QualityUnsigned Short11:Economy, 2:Normal, 3:Fine
0x0003Focusing ModeUnsigned Short12:Macro, 3:Auto Focus, 4:Manual Focus, 5:Infinity
0x0004Flash ModeUnsigned Short11:Auto, 2:On, 3:Off, 4:Red Eye Reduction
0x0005Flash IntensityUnsigned Short111:Weak, 13:Normal, 15:Strong
0x0006Object distanceUnsigned Long1Object distance in [mm]
0x0007White BalanceUnsigned Short11:Auto, 2:Tungsten, 3:Daylight, 4:Fluorescent, 5:Shade, 129:Manual
0x0008UnknownUnsigned short1Unknown
0x0009UnknownUnsigned short1Unknown
0x000aDigital ZoomUnsigned Long10x10000(65536):'Off', 0x10001(65537):'2X Digital Zoom'
0x000bSharpnessUnsigned Short10:Normal, 1:Soft, 2:Hard
0x000cContrastUnsigned Short10:Normal, 1:Low, 2:High
0x000dSaturationUnsigned Short10:Normal, 1:Low, 2:High
0x000eUnknownUnsigned short1Unknown
0x000fUnknownUnsigned short1Unknown
0x0010UnknownUnsigned short1Unknown
0x0011UnknownUnsigned long1Unknown
0x0012UnknownUnsigned short1Unknown
0x0013UnknownUnsigned short1Unknown
0x0014CCD SensitivityUnsigned short1QV3000:   64:Normal, 125:+1.0, 250:+2.0, 244:+3.0
QV8000/2000:   80:Normal, 100:High


Appendix 4: MakerNote of Fujifilm


Fujifilm's digicam added the MakerNote tag from the Year2000's model (e.g.Finepix1400,Finepix4700). It uses IFD format and start from ASCII character 'FUJIFILM', and next 4 bytes(value 0x000c) points the offset to first IFD entry. Example of actual data structure is shown below.
:0000: 46 55 4A 49 46 49 4C 4D-0C 00 00 00 0F 00 00 00 :0000: FUJIFILM........
            :0010: 07 00 04 00 00 00 30 31-33 30 00 10 02 00 08 00 :0010: ......0130......
            

There are two big differences to the other manufacturers.
  • Fujifilm's Exif data uses Motorola align, but MakerNote ignores it and uses Intel align.
  • The other manufacturer's MakerNote counts the "offset to data" from the first byte of TIFF header (same as the other IFD), but Fujifilm counts it from the first byte of MakerNote itself.
I think it's a BUG, but it can't be helped now... The data below is analyzed at Fujifilm FinePix4900Z.


Tag No.Tag NameFormatCompoNoValue
0x0000VersionUndefined4Version of MakerNote information. At present, value is "0130".
0x1000QualityAscii string8Quality setting. Ascii string "BASIC","NORMAL","FINE"
0x1001SharpnessUnsigned Short1Sharpness setting. 1or2:soft, 3:normal, 4or5:hard.
0x1002White BalanceUnsigned Short1White balance setting. 0:Auto, 256:Daylight, 512:Cloudy, 768:DaylightColor-fluorescence, 769:DaywhiteColor-fluorescence, 770:White-fluorescence, 1024:Incandenscense, 3840:Custom white balance.
0x1003ColorUnsigned Short1Chroma saturation setting. 0:normal(STD), 256:High, 512:Low(ORG).
0x1004ToneUnsigned Short1Contrast setting. 0:normal(STD), 256:High(HARD), 512:Low(ORG).
0x1010Flash ModeUnsigned Short1Flash firing mode setting. 0:Auto, 1:On, 2:Off, 3:Red-eye reduction.
0x1011Flash StrengthSigned Rational1Flash firing strength compensation setting. Unit is APEX(EV) and value is -6/10, -3/10, 0/10, 3/10, 6/10 etc.
0x1020MacroUnsigned Short1Macro mode setting. 0:Off, 1:On.
0x1021Focus modeUnsigned short1Focusing mode setting. 0:Auto focus, 1:Manual focus.
0x1030SlowSync.Unsigned short1Slow synchro mode setting. 0:Off, 1:On.
0x1031Picture ModeUnsigned short1Picture mode setting. 0:Auto, 1:Portrait scene, 2:Landscape scene, 4:Sports scene, 5:Night scene, 6:Program AE, 256:Aperture prior AE, 512:Shutter prior AE, 768:Manual exposure.
0x1032unknownUnsigned Short1Unknown
0x1100ContTake/BracketUnsigned Short1Continuous taking or auto bracketting mode setting. 0:off, 1:on.
0x1200unknownUnsigned Short1Unknown
0x1300Blur warningUnsigned Short1Blur warning status. 0:No blur warning, 1:Blur warning.
0x1301Focus warningUnsigned short1Auto Focus warning status. 0:Auto Focus good, 1:Out of focus.
0x1302AE warningUnsigned short1Auto Exposure warning status. 0:AE good, 1:Over exposure (>1/1000s,F11).

Appendix 5: MakerNote of Canon

The data below was primarily analysed by  David Burren  and the master version of this information is available at:  http://www.burren.cx/david/canon.html . Please send any updates to  David
This document is based on his Rev.1.11(2001/01/30) of document.

Canon's MakerNote data is in IFD format, starting at offset 0.

Some of these tags and fields are only produced on cameras such as the EOS D30, but (to current observation) all this is valid for all Canon digicams (at least since the A50). If the tag is not found, or is shorter than shown here, it simply means that data is not supported by that camera.

Tag No.Tag NameFormatCompoNoValue
0x0UnknownUnsigned Short6Always 0
0x1UnknownUnsigned Shortvaries
Offset within tagMeaning
0Length of tag in bytes (i.e. twice the number of shorts)
1Macro mode1: macro
2: normal
2If non-zero, length of self-timer in 10ths of a second
3unknown
4Flash mode0: flash not fired
1: auto
2: on
3: red-eye reduction
4: slow synchro
5: auto + red-eye reduction
6: on + red-eye reduction
16: external flash (not set on D30)
5Continuous drive mode0: single or timer (see field 2)
1: continuous
6unknown
7Focus Mode0: One-Shot
1: AI Servo
2: AI Focus
3: MF
4: Single (but check field 32)
5: Continuous
6: MF
8, 9unknown
10Image size0: large
1: medium
2: small
11"Easy shooting" mode0: Full Auto
1: Manual
2: Landscape
3: Fast Shutter
4: Slow Shutter
5: Night
6: B&W
7: Sepia
8: Portrait
9: Sports
10: Macro / Close-Up
11: Pan Focus
12unknown
13Contrast0xffff: low
0x0000: normal
0x0001: high
14Saturation0xffff: low
0x0000: normal
0x0001: high
15Sharpness0xffff: low
0x0000: normal
0x0001: high
16ISOIf zero, use ISOSpeedRatings EXIF tag instead
15: auto
16: 50
17: 100
18: 200
19: 400
17Metering mode3: Evaluative
4: Partial
5: Center-weighted
18unknown
19AF point selected0x3000: none (MF)
0x3001: auto-selected
0x3002: right
0x3003: center
0x3004: left
20Exposure mode0: "Easy shooting" (use field 11)
1: Program
2: Tv-priority
3: Av-priority
4: Manual
5: A-DEP
21, 22unknown
23"long" focal length of lens (in "focal units")
24"short" focal length of lens (in "focal units")
25"focal units" per mm
26 - 28unknown
29Flash detailsBits 15..0:
14: external E-TTL
13: internal flash
11: FP sync used
4: FP sync enabled
other bits unknown
30 - 31unknown
32Focus modeG1 seems to use this in preference to field 7
0: Single
1: Continuous
0x3UnknownUnsigned Short4unknown
0x4UnknownUnsigned Shortvaries
Offset within tagMeaning
0Length of tag in bytes (i.e. twice the number of shorts)
1 - 6unknown
7White balance0: auto
1: Sunny
2: Cloudy
3: Tungsten
4: Flourescent
5: Flash
6: Custom
8unknown
9Sequence number (if in a continuous burst)
10 - 13unknown
14AF point usedOnly set in One-Shot mode?
If none used, AF failed or manual focus was used (e.g. on a lens with full-time manual focus) 
Bits 15..0:
15-12: number of available focus points
2: left
1: center
0: right
15Flash bias0xffc0: -2 EV
0xffcc: -1.67 EV
0xffd0: -1.50 EV
0xffd4: -1.33 EV
0xffe0: -1 EV
0xffec: -0.67 EV
0xfff0: -0.50 EV
0xfff4: -0.33 EV
0x0000: 0 EV
0x000c: 0.33 EV
0x0010: 0.50 EV
0x0014: 0.67 EV
0x0020: 1 EV
0x002c: 1.33 EV
0x0030: 1.50 EV
0x0034: 1.67 EV
0x0040: 2 EV
16 - 18unknown
19Subject DistanceUnits are either 0.01m or 0.001m (both have been observed). Still investigating. 
In any case, the SubjectDistance EXIF tag is set by Canon cameras.
0x6Image typeAscii string32e.g.: "IMG:EOS D30 JPEG"
Has trailing whitespace.
0x7Firmware versionAscii string24May have trailing NULs and whitespace.
0x8Image NumberUnsigned Long1Normally reported as FFF-XXXX. 
FFF is this value divided by 1000, XXXX is this value mod 1000.
0x9Owner nameAscii string32May have trailing NULs and whitespace.
0xaUnknownUnsigned Shortvariesunknown
0xcCamera serial numberUnsigned Long1High 16 bits are printed as a 4-digit hex number. 
Low 16 bits are printed as a 5-digit decimal number. 
These are concatenated to form the serial number. Example printf() format string would be "%04X%05d".
0xdUnknownUnsigned Shortvariesunknown
0xfCustom FunctionsUnsigned ShortvariesFirst short is the number of bytes in the tag (i.e. twice the number of shorts) 
For each other value: the top 8 bits are the C.Fn number, and the lower 8 bits are the value.

EOS D30 Custom Functions

C.FnNameValue
1Long exposure noise reduction0: Off
1: On
2Shutter/AE-lock buttons0: AF/AE lock
1: AE lock/AF
2: AF/AF lock
3: AE+release/AE+AF
3Mirror lockup0: Disable
1: Enable
4Tv/Av and exposure level0: 1/2 stop
1: 1/3 stop
5AF-assist light0: On (auto)
1: Off
6Shutter speed in Av mode0: Automatic
1: 1/200 (fixed)
7AEB sequence/auto cancellation0: 0, -, + / Enabled
1: 0, -, + / Disabled
2: -, 0, + / Enabled
3: -, 0, + / Disabled
8Shutter curtain sync0: 1st-curtain sync
1: 2nd-curtain sync
9Lens AF stop button Fn. Switch0: AF stop
1: Operate AF
2: Lock AE and start timer
10Auto reduction of fill flash0: Enable
1: Disable
11Menu button return position0: Top
1: Previous (volatile)
2: Previous
12SET button func. when shooting0: Not assigned
1: Change quality
2: Change ISO speed
3: Select parameters
13Sensor cleaning0: Disable
1: Enable



修订履历

rev. 1.4

  • 追加了佳能的Makernote
  • 在富士的makernote中增加了色彩/色调 标签

rev. 1.3

  • 追加了 Exif2.1 规格
  • 添加了富士的 Makernote

rev. 1.2

  • 追加了 DCF 规格
  • 追加了Interoperability IFD
  • 添加了尼康/卡西欧的Makernote

rev. 1.1

  • 在TIFF头的标签标记中追加了字节顺序的解释
  • 为"unsigned short/long"修正了一些标签的数据格式
  • 修正了FocalPlaneResolutionUnit的值
  • 附录1: 奥林帕斯的MakerNote

rev. 1.0

  • 第一版发布


我想要感谢;

Daniel Switkin: 标签标记的字节序, ImageWidth/ImageLeng格式
Peter Esherick: 奥林帕斯的MakerNote
Matthias Wandel: FocalPlaneResolutionUnit的值
Max Lyons : 尼康的Makernote   ...它的  网页 在这里
Eckhard Henkel : 卡西欧的Makernote   ...它的  网页 在这里
David Burren : 富士的FocalPlaneResolutionUnit的值 / 佳能的Makernote  ...它的  网页 在这里


tga文件格式

分类: 游戏编程   65人阅读  评论(0)  收藏  举报

Tga常见的格式有非压缩RGB和压缩RGB两种格式,文件的第三个Byte位作为标记:2为非压缩RGB格式,10为压缩RGB格式。这里的类只实现读取非压缩格式的tga文件。

先给出tga文件的文件格式:

名称

偏移

长度

说明

图像信息字段长度

0

1

本字段是 1 字节无符号整型,指出图像信息字段(见本子表的后面)长度,其取值范围是 0  255 ,当它为 0 时表示没有图像的信息字段。

颜色表类型

1

1

表示没有颜色表,表示颜色表存在。由于本格式是无颜色表的,因此此项通常被忽略。

图像类型码

2

1

该字段总为 2 ,这也是此类型为格式 2 的原因。

颜色表规格字段

颜色表首址

3

2

颜色表首的入口索引,整型(低位-高位)

如果颜色表字段为0,则忽略该字段

颜色表的长度

5

2

颜色表的表项总数,整型(低位-高位)

颜色表项位数

7

1

位数(bit),16 代表 16  TGA 24 代表 24  TGA 32 代表 32 TGA

图像规格字段

图像 X 坐标起始位置

8

2

图像左下角 X坐标的整型(低位-高位)值

图像 Y 坐标起始位置

10

2

图像左下角 Y坐标的整型(低位-高位)值

图像宽度

12

2

以像素为单位,图像宽度的整型(低位-高位)

图像高度

14

2

以像素为单位,图像宽度的整型(低位-高位)

图像每像素存储占用位数

16

2

它的值为1624  32 等等。决定了该图像是 TGA 16TGA24,TGA 32 等等。

图像描述符字节

17

1

bits 3-0 - 每像素对应的属性位的位数;

对于TGA 16,该值为 0  1,对于 TGA                     24,该值为 0,对于 TGA 32,该值为 8

 

bit 4    - 保留,必须为 0

 

bit 5    - 屏幕起始位置标志

0 = 原点在左下角

1 = 原点在左上角

对于 truevision 图像必须为 0

 

bits 7-6 - 交叉数据存储标志

00 = 无交叉

01 = 两路奇/偶交叉

10 = 四路交叉

11 = 保留

图像信息字段

18

可变

包含一个自由格式的,长度是图像由“图像信息字段”指定。它常常被忽略(即偏移 0 处值为 0 ),注意其最大可以含有 255 个字符。如果需要存储更多信息,可以放在图像数据之后。

颜色表数据

可变

可变

如果颜色表类型为 0,则该域不存在,否则越过该域直接读取图像颜色表规格中描述了每项的字节数,为23之一。

图像数据

可变

可变

RGB颜色数据,存放顺序为:BBB GGG RRR (AAA)


 

PNG图片分析(汇总)

分类: j2me   1010人阅读  评论(0)  收藏  举报

我们都知道,在进行J2ME的手机应用程序开发的时候,在图片的使用上,我们可以使用PNG格式的图片(甚至于在有的手机上,我们只可以使用PNG格式的图片),尽管使用图片可以为我们的应用程序增加不少亮点,然而,只支持PNG格式的图片却又限制了我们进一步发挥的可能性(其实,应该说是由于手机平台上的处理能力有限)。 在MIDP2中,或者某些厂商(如NOKIA)提供的API中,提供了drawPixels/getPixels的方法,这些方法进一步提高了开发者处理图片的灵活性,然而,在MIDP2还未完全普及的今天,我们需要在MIDP1 .0中实现这类方法还属于异想天开,因此,为了实现更高级的应用,我们必须充分挖掘PNG的潜力。

PNG的文件结构

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

十进制数137 80 78 71 13 10 26 10
十六进制数89 50 4E 47 0D 0A 1A 0A

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

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

PNG数据块(Chunk)

PNG定义了两种类型的数据块,一种是称为关键数据块(critical chunk),这是标准的数据块,另一种叫做辅助数据块(ancillary chunks),这是可选的数据块。关键数据块定义了4个标准数据块,每个PNG文件都必须包含它们,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个数据块按以上先后顺序进行存储,并且都只出现一次。

数据块结构

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

下面,我们依次来了解一下各个关键数据块的结构吧。

IHDR

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

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

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

由于我们研究的是手机上的PNG,因此,首先我们看看MIDP1.0对所使用PNG图片的要求吧:

  • 在MIDP1.0中,我们只可以使用1.0版本的PNG图片。并且,所以的PNG关键数据块都有特别要求:
    IHDR
  • 文件大小:MIDP支持任意大小的PNG图片,然而,实际上,如果一个图片过大,会由于内存耗尽而无法读取。
  • 颜色类型:所有颜色类型都有被支持,虽然这些颜色的显示依赖于实际设备的显示能力。同时,MIDP也能支持alpha通道,但是,所有的alpha通道信息都会被忽略并且当作不透明的颜色对待。
  • 色深:所有的色深都能被支持。
  • 压缩方法:仅支持压缩方式0(deflate压缩方式),这和jar文件的压缩方式完全相同,所以,PNG图片数据的解压和jar文件的解压可以使用相同的代码。(其实这也就是为什么J2ME能很好的支持PNG图像的原因:))
  • 滤波器方法:尽管在PNG的白皮书中仅定义了方法0,然而所有的5种方法都被支持!
  • 隔行扫描:虽然MIDP支持0、1两种方式,然而,当使用隔行扫描时,MIDP却不会真正的使用隔行扫描方式来显示。
  • PLTE chunk:支持
  • IDAT chunk:图像信息必须使用5种过滤方式中的方式0 (None, Sub, Up, Average, Paeth)
  • IEND chunk:当IEND数据块被找到时,这个PNG图像才认为是合法的PNG图像。
  • 可选数据块:MIDP可以支持下列辅助数据块,然而,这却不是必须的。

    bKGD cHRM gAMA hIST iCCP iTXt pHYs
    sBIT sPLT sRGB tEXt tIME tRNS zTXt

关于更多的信息,可以参考http://www.w3.org/TR/REC-png.html

PLTE

调色板数据块PLTE(palette chunk)包含有与索引彩色图像(indexed-color image)相关的彩色变换数据,它仅与索引彩色图像有关,而且要放在图像数据块(image data chunk)之前。

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

颜色

字节

意义

Red

1 byte

0 = 黑色, 255 = 红

Green

1 byte

0 = 黑色, 255 = 绿色

Blue

1 byte

0 = 黑色, 255 = 蓝色

因此,调色板的长度应该是3的倍数,否则,这将是一个非法的调色板。

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

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

IDAT

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

IDAT存放着图像真正的数据信息,因此,如果能够了解IDAT的结构,我们就可以很方便的生成PNG图像。

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。

实例研究PNG

以下是由Fireworks生成的一幅图像,图像大小为8*8,为了方便大家观看,我们将图像放大:



使用UltraEdit32打开该文件,如下:
00000000~00000007:

可以看到,选中的头8个字节即为PNG文件的标识。

接下来的地方就是IHDR数据块了:

00000008~00000020:

  • 00 00 00 0D 说明IHDR头块长为13
  • 49 48 44 52 IHDR标识
  • 00 00 00 08 图像的宽,8像素
  • 00 00 00 08 图像的高,8像素
  • 04 色深,2^4=16,即这是一个16色的图像(也有可能颜色数不超过16,当然,如果颜色数不超过8,用03表示更合适)
  • 03 颜色类型,索引图像
  • 00 PNG Spec规定此处总为0(非0值为将来使用更好的压缩方法预留),表示使压缩方法(LZ77派生算法)
  • 00 同上
  • 00 非隔行扫描
  • 36 21 A3 B8 CRC校验

00000021~0000002F:

可选数据块sBIT,颜色采样率,RGB都是256(2^8=256)

00000030~00000062:

这里是调色板信息

  • 00 00 00 27 说明调色板数据长为39字节,既13个颜色数
  • 50 4C 54 45 PLTE标识
  • FF FF 00 颜色0
  • FF ED 00 颜色1
  • …… ……
  • 09 00 B2 最后一个颜色,12
  • 5F F5 BB DD CRC校验

00000063~000000C5:

这部分包含了pHYs、tExt两种类型的数据块共3块,由于并不太重要,因此也不再详细描述了。

000000C0~000000F8:

以上选中部分是IDAT数据块

  • 00 00 00 27 数据长为39字节
  • 49 44 41 54 IDAT标识
  • 78 9C…… 压缩的数据,LZ77派生压缩方法
  • DA 12 06 A5 CRC校验

IDAT中压缩数据部分在后面会有详细的介绍。

000000F9~00000104:

IEND数据块,这部分正如上所说,通常都应该是

00 00 00 00 49 45 4E 44 AE 42 60 82

至此,我们已经能够从一个PNG文件中识别出各个数据块了。由于PNG中规定除关键数据块外,其它的辅助数据块都为可选部分,因此,有了这个标准后,我们可以通过删除所有的辅助数据块来减少PNG文件的大小。(当然,需要注意的是,PNG格式可以保存图像中的层、文字等信息,一旦删除了这些辅助数据块后,图像将失去原来的可编辑性。)

删除了辅助数据块后的PNG文件,现在文件大小为147字节,原文件大小为261字节,文件大小减少后,并不影响图像的内容。

 

 

如上说过,IDAT数据块是使用了LZ77压缩算法生成的,由于受限于手机处理器的能力,因此,如果我们在生成IDAT数据块时仍然使用LZ77压缩算法,将会使效率大打折扣,因此,为了效率,只能使用无压缩的LZ77算法,关于LZ77算法的具体实现,此文不打算深究,如果你对LZ77算法的JAVA实现有兴趣,可以参考以下两个站点:

参考资料:

PNG文件格式白皮书:http://www.w3.org/TR/REC-png.html
为数不多的中文PNG格式说明:http://dev.gameres.com/Program/Visual/Other/PNGFormat.htm
RFC-1950(ZLIB Compressed Data Format Specification):ftp://ds.internic.net/rfc/rfc1950.txt
RFC-1950(DEFLATE Compressed Data Format Specification):ftp://ds.internic.net/rfc/rfc1951.txt
LZ77算法的JAVA实现:http://jazzlib.sourceforge.net/
LZ77算法的JAVA实现,包括J2ME版本:http://www.jcraft.com/jzlib/index.html

 

 


 上面我们已经对PNG的存储格式有了了解,因此,生成PNG图片只需要按照以上的数据块写入文件即可。 (由于IHDR、PLTE的结构都非常简单,因此,这里我们只是重点讲一讲IDAT的生成方法,IHDR和PLTE的数据内容都沿用以上的数据内容)
问题确实是这样的,我们知道,对于大多数的图形文件来说,我们都可以将实际的图像内容映射为一个二维的颜色数组,对于上面的PNG文件,由于它用的是16色的调色板(实际是13色),因此,对于图片的映射可以如下:

图-1
(调色板对照图)

12 11 10 9 8 7 6 5 11 10 9 8 7 6 5 4 10 9 8 7 6 5 4 3 9 8 7 6 5 4 3 2 8 7 6 5 4 3 2 1 7 6 5 4 3 2 1 0 6 5 4 3 2 1 0 0 5 4 3 2 1 0 0 0 PNG Spec中指出,假如PNG文件不是采用隔行扫描方法存储的话,那么,数据是按照行(ScanLine)来存储的,为了区分第一行,PNG规定在每一行的前面加上0以示区分,因此,上面的图像映射应该如下:
0 12 11 10 9 8 7 6 5 0 11 10 9 8 7 6 5 4 0 10 9 8 7 6 5 4 3 0 9 8 7 6 5 4 3 2 0 8 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 0 6 5 4 3 2 1 0 0 0 5 4 3 2 1 0 0 0 另外,需要注重的是,由于PNG在存储图像时为了节省空间,因此每一行是按照位(Bit)来存储的,而并不是我们想象的字节(Byte),假如你没有忘记的话,我们的IHDR数据块中的色深就指明了这一点,所以,为了凑成PNG所需要的IDAT,我们的数据得改成如下:
0 203 169 135 101 0 186 152 118 84 0 169 135 101 67 0 152 118 84 50 0 135 101 67 33 0 118 84 50 16 0 101 67 33 0 0 84 50 16 0最后,我们对这些数据进行LZ77压缩就可以得到IDAT的正确内容了。
然而,事情并不是这么简单,因为我们研究的是手机上的PNG,假如需要在手机上完成LZ77压缩工作,消耗的时间是可想而知的,因此,我们得再想办法加减少压缩时消耗的时间。
好在LZ77也提供了无压缩的压缩方法(希奇吧?),因此,我们只需要简单的使用无压缩的方式写入数据就可以了,这样虽然浪费了空间,却换回了时间!
好了,让我们看一看怎么样凑成无压缩的LZ77压缩块:
字节意义0~2压缩信息,固定为0x78, 0xda, 0x13~6压缩块的LEN和NLEN信息压缩的数据最后4字节Adler32信息其中的LEN是指数据的长度,占用两个字节,对于我们的图像来说,第一个Scan Line包含了5个字节(如第一行的0, 203, 169, 135, 101),所以LEN的值为5(字节/行) * 8(行) = 40(字节),生成字节为28 00(低字节在前),NLEN是LEN的补码,即NLEN = LEN ^ 0xFFFF,所以NLEN的为 D7 FF,Adler32信息为24 A7 0B A4(具体算法见源程序),因此,按照这样的顺序,我们生成IDAT数据块,最后,我们将IHDR、PLTE、IDAT和IEND数据块写入文件中,就可以得到PNG文件了,如图:

 

图-2


(选中的部分为生成的“压缩”数据)

至此,我们已经能够采用最快的时间将数组转换为PNG图片了。
生成的PNG文件:
范例(附源程序)


GIF文件格式解析

分类: 文件格式   34人阅读  评论(0)  收藏  举报

1.概述
~~~~~~~~

  GIF(Graphics Interchange Format,图形交换格式)文件是由 CompuServe公司开发的图形文件格式,版权所有,任何商业目的使用均须 CompuServe公司授权。
  GIF图象是基于颜色列表的(存储的数据是该点的颜色对应于颜色列表的索引值),最多只支持8位(256色)。GIF文件内部分成许多存储块,用来存储多幅图象或者是决定图象表现行为的控制块,用以实现动画和交互式应用。GIF文件还通过LZW压缩算法压缩图象数据来减少图象尺寸(关于
LZW算法和GIF数据压缩>>...)。

2.GIF文件存储结构
~~~~~~~~~~~~~~~~~~~

  GIF文件内部是按块划分的,包括控制块( Control Block )和数据块(Data Sub-blocks)两种。控制块是控制数据块行为的,根据不同的控制块包含一些不同的控制参数;数据块只包含一些8-bit的字符流,由它前面的控制块来决定它的功能,每个数据块大小从0到255个字节,数据块的第一个字节指出这个数据块大小(字节数),计算数据块的大小时不包括这个字节,所以一个空的数据块有一个字节,那就是数据块的大小0x00。下表是一个数据块的结构:

BYTE76543210BIT
0

块大小

Block Size - 块大小,不包括这个这个字节(不计算块大小自身)
1 Data Values - 块数据,8-bit的字符串
2 
... 
254 
255 

  一个GIF文件的结构可分为文件头(File Header)、GIF数据流(GIF Data Stream)和文件终结器(Trailer)三个部分。文件头包含GIF文件署名(Signature)和版本号(Version);GIF数据流由控制标识符、图象块(Image Block)和其他的一些扩展块组成;文件终结器只有一个值为0x3B的字符(';')表示文件结束。下表显示了一个GIF文件的组成结构:

 GIF署名文件头 
 版本号
 逻辑屏幕标识符GIF数据流 
 全局颜色列表 
 ... 
 图象标识符图象块                             
 图象局部颜色列表图
                           基于颜色列表的图象数据 
 
 ... 
 GIF结尾文件结尾 

  下面就具体介绍各个部分:

文件头部分(Header)
~~~~~~~~~~~~~~~~~

GIF署名(Signature)和版本号(Version)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
GIF署名用来确认一个文件是否是GIF格式的文件,这一部分由三个字符组成:"GIF";文件版本号也是由三个字节组成,可以为"87a"或"89a".具体描述见下表:

BYTE76543210BIT
1'G'GIF文件标识
2'I'
3'F'
4'8'GIF文件版本号:87a - 1987年5月
        89a - 1989年7月
5'7'或'9'
6'a'

GIF数据流部分(GIF Data Stream)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

逻辑屏幕标识符(Logical Screen Descriptor)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
这一部分由7个字节组成,定义了GIF图象的大小(Logical Screen Width & Height)、颜色深度(Color Bits)、背景色(Blackground Color Index)以及有无全局颜色列表(Global Color Table)和颜色列表的索引数(Index Count),具体描述见下表:

BYTE76543210BIT 
1逻辑屏幕宽度像素数,定义GIF图象的宽度
2
3逻辑屏幕高度像素数,定义GIF图象的高度
4
5mcrspixel具体描述见下...
6背景色背景颜色(在全局颜色列表中的索引,如果没有全局颜色列表,该值没有意义)
7像素宽高比像素宽高比(Pixel Aspect Radio)

m - 全局颜色列表标志(Global Color Table Flag),当置位时表示有全局颜色列表,pixel值有意义.
cr - 颜色深度(Color ResoluTion),cr+1确定图象的颜色深度.
s - 分类标志(Sort Flag),如果置位表示全局颜色列表分类排列.
pixel - 全局颜色列表大小,pixel+1确定颜色列表的索引数(2的pixel+1次方).

全局颜色列表(Global Color Table)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
全局颜色列表必须紧跟在逻辑屏幕标识符后面,每个颜色列表索引条目由三个字节组成,按R、G、B的顺序排列。

BYTE76543210BIT
1索引1的红色值 
2索引1的绿色值 
3索引1的蓝色值 
4索引2的红色值 
5索引2的绿色值 
6索引2的蓝色值 
7...                            

图象标识符(Image Descriptor)
~~~~~~~~~~~~~~~~~~~~~~~~~
一个GIF文件内可以包含多幅图象,一幅图象结束之后紧接着下是一幅图象的标识符,图象标识符以0x2C(',')字符开始,定义紧接着它的图象的性质,包括图象相对于逻辑屏幕边界的偏移量、图象大小以及有无局部颜色列表和颜色列表大小,由10个字节组成:

BYTE76543210BIT 
100101100图象标识符开始,固定值为','
2X方向偏移量必须限定在逻辑屏幕尺寸范围内
3
4Y方向偏移量
5
6图象宽度
7
8图象高度
9
10misrpixelm - 局部颜色列表标志(Local Color Table Flag)
       置位时标识紧接在图象标识符之后有一个局部颜色列表,供紧跟在它之后的一幅图象使用;值否时使用全局颜色列表,忽略pixel值。
i - 交织标志(Interlace Flag),置位时图象数据使用交织方式排列(
详细描述...),否则使用顺序排列。
s - 分类标志(Sort Flag),如果置位表示紧跟着的局部颜色列表分类排列.
r - 保留,必须初始化为0.
pixel - 局部颜色列表大小(Size of Local Color Table),pixel+1就为颜色列表的位数

局部颜色列表(Local Color Table)
~~~~~~~~~~~~~~~~~~~~~~~~~~
如果上面的局部颜色列表标志置位的话,则需要在这里(紧跟在图象标识符之后)定义一个局部颜色列表以供紧接着它的图象使用,注意使用前应线保存原来的颜色列表,使用结束之后回复原来保存的全局颜色列表。如果一个GIF文件即没有提供全局颜色列表,也没有提供局部颜色列表,可以自己创建一个颜色列表,或使用系统的颜色列表。局部颜色列表的排列方式和全局颜色列表一样:RGBRGB......

基于颜色列表的图象数据(Table-Based Image Data)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
由两部分组成:LZW编码长度(LZW Minimum Code Size)和图象数据(Image Data)。

BYTE76543210BIT
1LZW编码长度LZW编码初始码表大小的位数,详细描述见LZW编码...
 

 


...
图象数据,由一个或几个数据块(Data Sub-blocks)组成

数据块

...

GIF图象数据使用了LZW压缩算法(详细介绍请看后面的『LZW算法和GIF数据压缩』),大大减小了图象数据的大小。图象数据在压缩前有两种排列格式:连续的和交织的(由图象标识符的交织标志控制)。连续方式按从左到右、从上到下的顺序排列图象的光栅数据;交织图象按下面的方法处理光栅数据:

创建四个通道(pass)保存数据,每个通道提取不同行的数据:
第一通道(Pass 1)提取从第0行开始每隔8行的数据;
第二通道(Pass 2)提取从第4行开始每隔8行的数据;
第三通道(Pass 3)提取从第2行开始每隔4行的数据;
第四通道(Pass 4)提取从第1行开始每隔2行的数据;

下面的例子演示了提取交织图象数据的顺序:

 通道1  通道2  通道3  通道4  
0  --------------------------------------------------------1    
1 --------------------------------------------------------   4 
2  --------------------------------------------------------  3  
3  --------------------------------------------------------   4 
4  -------------------------------------------------------- 2   
5  --------------------------------------------------------   4 
6  --------------------------------------------------------  3  
7  --------------------------------------------------------   4 
8  --------------------------------------------------------1    
9  --------------------------------------------------------   4 
10 --------------------------------------------------------  3  
11 --------------------------------------------------------   4 
12 -------------------------------------------------------- 2   
13 --------------------------------------------------------   4 
14 --------------------------------------------------------  3  
15 --------------------------------------------------------   4 
16 --------------------------------------------------------1    
17 --------------------------------------------------------   4 
18 --------------------------------------------------------  3  
19 --------------------------------------------------------   4 
20 -------------------------------------------------------- 2   

 

图形控制扩展(Graphic Control Extension)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
这一部分是可选的(需要89a版本),可以放在一个图象块(图象标识符)或文本扩展块的前面,用来控制跟在它后面的第一个图象(或文本)的渲染(Render)形式,组成结构如下:

BYTE76543210BIT
1扩展块标识Extension Introducer - 标识这是一个扩展块,固定值0x21
2图形控制扩展标签Graphic Control Label - 标识这是一个图形控制扩展块,固定值0xF9
3块大小Block Size - 不包括块终结器,固定值4
4保留处置方法

i

t

i - 用户输入标志;t - 透明色标志。详细描述见下...
5延迟时间Delay Time - 单位1/100秒,如果值不为1,表示暂停规定的时间后再继续往下处理数据流
6
7透明色索引Transparent Color Index - 透明色索引值
8块终结器Block Terminator - 标识块终结,固定值0

处置方法(Disposal Method):指出处置图形的方法,当值为:
                        0 - 不使用处置方法
                        1 - 不处置图形,把图形从当前位置移去
                        2 - 回复到背景色
                        3 - 回复到先前状态
                      4-7 - 自定义
用户输入标志(Use Input Flag):指出是否期待用户有输入之后才继续进行下去,置位表示期待,值否表示不期待。用户输入可以是按回车键、鼠标点击等,可以和延迟时间一起使用,在设置的延迟时间内用户有输入则马上继续进行,或者没有输入直到延迟时间到达而继续
透明颜色标志(Transparent Color Flag):置位表示使用透明颜色

注释扩展(Comment Extension)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
这一部分是可选的(需要89a版本),可以用来记录图形、版权、描述等任何的非图形和控制的纯文本数据(7-bit ASCII字符),注释扩展并不影响对图象数据流的处理,解码器完全可以忽略它。存放位置可以是数据流的任何地方,最好不要妨碍控制和数据块,推荐放在数据流的开始或结尾。具体组成:

BYTE76543210BIT
1扩展块标识Extension Introducer - 标识这是一个扩展块,固定值0x21
2注释块标签Comment Label - 标识这是一个注释块,固定值0xFE
 
...
Comment Data - 一个或多个数据块(Data Sub-Blocks)组成

注释块

...
 块终结器Block Terminator - 标识注释块结束,固定值0

图形文本扩展(Plain Text Extension)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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

BYTE76543210BIT
1扩展块标识Extension Introducer - 标识这是一个扩展块,固定值0x21
2图形控制扩展标签Plain Text Label - 标识这是一个图形文本扩展块,固定值0x01
3块大小Block Size - 块大小,固定值12
4文本框左边界位置Text Glid Left Posotion - 像素值,文本框离逻辑屏幕的左边界距离
5
6文本框上边界位置Text Glid Top Posotion - 像素值,文本框离逻辑屏幕的上边界距离
7
8文本框高度Text Glid Width -像素值
9
10文本框高度Text Glid Height - 像素值
11
12字符单元格宽度Character Cell Width - 像素值,单个单元格宽度
13字符单元格高度Character Cell Height- 像素值,单个单元格高度
14文本前景色索引Text Foreground Color Index - 前景色在全局颜色列表中的索引
15文本背景色索引Text Blackground Color Index - 背景色在全局颜色列表中的索引
N
...
Plain Text Data - 一个或多个数据块(Data Sub-Blocks)组成,保存要在显示的字符串。

文本数据块

...
N+1块终结Block Terminator - 标识注释块结束,固定值0

推荐:1.由于文本的字体(Font)和尺寸(Size)没有定义,解码器应该根据情况选择最合适的;
2.如果一个字符的值小于0x20或大于0xF7,则这个字符被推荐显示为一个空格(0x20);
3.为了兼容性,最好定义字符单元格的大小为8x8或8x16(宽度x高度)。

应用程序扩展(Application Extension)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

这是提供给应用程序自己使用的(需要89a版本),应用程序可以在这里定义自己的标识、信息等,组成:

BYTE76543210BIT
1扩展块标识Extension Introducer - 标识这是一个扩展块,固定值0x21
2图形控制扩展标签Application Extension Label - 标识这是一个应用程序扩展块,固定值0xFF
3块大小Block Size - 块大小,固定值11
4应用程序标识符Application Identifier - 用来鉴别应用程序自身的标识(8个连续ASCII字符)
5
6
7
8
9
10
11
12应用程序鉴别码Application Authentication Code - 应用程序定义的特殊标识码(3个连续ASCII字符)
13
14
N
...
应用程序自定义数据块 - 一个或多个数据块(Data Sub-Blocks)组成,保存应用程序自己定义的数据

应用程序数据

...
N+1块终结器lock Terminator - 标识注释块结束,固定值0

文件结尾部分
~~~~~~~~~~~

文件终结器(Trailer)
~~~~~~~~~~~~~~~~

这一部分只有一个值为0的字节,标识一个GIF文件结束.

BYTE76543210 
1

文件终结

GIF Trailer - 标识GIF文件结束,固定值0x3B

2.LZW算法和GIF数据压缩
~~~~~~~~~~~~~~~~~~~~~~~~~~~

  GIF文件的图象数据使用了可变长度编码的LZW压缩算法(Variable-Length_Code LZW Compression),这是从LZW(Lempel Ziv Compression)压缩算法演变过来的,通过压缩原始数据的重复部分来达到减少文件大小的目的。

标准的LZW压缩原理:
~~~~~~~~~~~~~~~~~~
先来解释一下几个基本概念:
  LZW压缩有三个重要的对象:数据流(CharStream)、编码流(CodeStream)和编译表(String Table)。在编码时,数据流是输入对象(图象的光栅数据序列),编码流就是输出对象(经过压缩运算的编码数据);在解码时,编码流则是输入对象,数据流是输出对象;而编译表是在编码和解码时都须要用借助的对象。

字符(Character):最基础的数据元素,在文本文件中就是一个字节,在光栅数据中就是一个像素的颜色在指定的颜色列表中的索引值;
字符串(String):由几个连续的字符组成;
前缀(Prefix):也是一个字符串,不过通常用在另一个字符的前面,而且它的长度可以为0;
根(Root):单个长度的字符串;
编码(Code):一个数字,按照固定长度(编码长度)从编码流中取出,编译表的映射值;
图案:一个字符串,按不定长度从数据流中读出,映射到编译表条目.

  LZW压缩的原理:提取原始图象数据中的不同图案,基于这些图案创建一个编译表,然后用编译表中的图案索引来替代原始光栅数据中的相应图案,减少原始数据大小。看起来和调色板图象的实现原理差不多,但是应该注意到的是,我们这里的编译表不是事先创建好的,而是根据原始图象数据动态创建的,解码时还要从已编码的数据中还原出原来的编译表(GIF文件中是不携带编译表信息的),为了更好理解编解码原理,我们来看看具体的处理过程:

编码器(Compressor)
~~~~~~~~~~~~~~~~

  编码数据,第一步,初始化一个编译表,假设这个编译表的大小是12位的,也就是最多有4096个单位,另外假设我们有32个不同的字符(也可以认为图象的每个像素最多有32种颜色),表示为a,b,c,d,e...,初始化编译表:第0项为a,第1项为b,第2项为c...一直到第31项,我们把这32项就称为根。
  开始编译,先定义一个前缀对象Current Prefix,记为[.c.],现在它是空的,然后定义一个当前字符串Current String,标记为[.c.]k,[.c.]就为Current Prefix,k就为当前读取字符。现在来读取数据流的第一个字符,假如为p,那么Current String就等于[.c.]p(由于[.c.]为空,实际上值就等于p),现在在编译表中查找有没有Current String的值,由于p就是一个根字符,我们已经初始了32个根索引,当然可以找到,把p设为Current Prefix的值,不做任何事继续读取下一个字符,假设为q,Current String就等于[.c.]q(也就是pq),看看在编译表中有没有该值,当然。没有,这时我们要做下面的事情:将Current String的值(也就是pq)添加到编译表的第32项,把Current Prefix的值(也就是p)在编译表中的索引输出到编码流,修改Current Prefix为当前读取的字符(也就是q)。继续往下读,如果在编译表中可以查找到Current String的值([.c.]k),则把Current String的值([.c.]k)赋予Current Prefix;如果查找不到,则添加Current String的值([.c.]k)到编译表,把Current Prefix的值([.c.])在编译表中所对应的索引输出到编码流,同时修改Current Prefix为k ,这样一直循环下去直到数据流结束。伪代码看起来就像下面这样:

编码器伪代码

Initialize String Table;
[.c.] = Empty;
[.c.]k = First Character in CharStream;
while ([.c.]k != EOF )
{
  if ( [.c.]k is in the StringTable)
  {
    [.c.] = [.c.]k;
  }
  else
  {
    add [.c.]k to the StringTable;
    Output the Index of [.c.] in the StringTable to the CodeStream;
    [.c.] = k;
  }
  [.c.]k = Next Character in CharStream;
}
Output the Index of [.c.] in the StringTable to the CodeStream;

来看一个具体的例子,我们有一个字母表a,b,c,d.有一个输入的字符流abacaba。现在来初始化编译表:#0=a,#1=b,#2=c,#3=d.现在开始读取第一个字符a,[.c.]a=a,可以在在编译表中找到,修改[.c.]=a;不做任何事继续读取第二个字符b,[.c.]b=ab,在编译表中不能找,那么添加[.c.]b到编译表:#4=ab,同时输出[.c.](也就是a)的索引#0到编码流,修改[.c.]=b;读下一个字符a,[.c.]a=ba,在编译表中不能找到:添加编译表#5=ba,输出[.c.]的索引#1到编码流,修改[.c.]=a;读下一个字符c,[.c.]c=ac,在编译表中不能找到:添加编译表#6=ac,输出[.c.]的索引#0到编码流,修改[.c.]=c;读下一个字符a,[.c.]c=ca,在编译表中不能找到:添加编译表#7=ca,输出[.c.]的索引#2到编码流,修改[.c.]=a;读下一个字符b,[.c.]b=ab,编译表的#4=ab,修改[.c.]=ab;读取最后一个字符a,[.c.]a=aba,在编译表中不能找到:添加编译表#8=aba,输出[.c.]的索引#4到编码流,修改[.c.]=a;好了,现在没有数据了,输出[.c.]的值a的索引#0到编码流,这样最后的输出结果就是:#0#1#0#2#4#0.

解码器(Decompressor)
~~~~~~~~~~~~~~~~~~

  好了,现在来看看解码数据。数据的解码,其实就是数据编码的逆向过程,要从已经编译的数据(编码流)中找出编译表,然后对照编译表还原图象的光栅数据。
  首先,还是要初始化编译表。GIF文件的图象数据的第一个字节存储的就是LZW编码的编码大小(一般等于图象的位数),根据编码大小,初始化编译表的根条目(从0到2的编码大小次方),然后定义一个当前编码Current Code,记作[code],定义一个Old Code,记作[old]。读取第一个编码到[code],这是一个根编码,在编译表中可以找到,把该编码所对应的字符输出到数据流,[old]=[code];读取下一个编码到[code],这就有两种情况:在编译表中有或没有该编码,我们先来看第一种情况:先输出当前编码[code]所对应的字符串到数据流,然后把[old]所对应的字符(串)当成前缀prefix [...],当前编码[code]所对应的字符串的第一个字符当成k,组合起来当前字符串Current String就为[...]k,把[...]k添加到编译表,修改[old]=[code],读下一个编码;我们来看看在编译表中找不到该编码的情况,回想一下编码情况:如果数据流中有一个p[...]p[...]pq这样的字符串,p[...]在编译表中而p[...]p不在,编译器将输出p[...]的索引而添加p[...]p到编译表,下一个字符串p[...]p就可以在编译表中找到了,而p[...]pq不在编译表中,同样将输出p[...]p的索引值而添加p[...]pq到编译表,这样看来,解码器总比编码器『慢一步』,当我们遇到p[...]p所对应的索引时,我们不知到该索引对应的字符串(在解码器的编译表中还没有该索引,事实上,这个索引将在下一步添加),这时需要用猜测法:现在假设上面的p[...]所对应的索引值是#58,那么上面的字符串经过编译之后是#58#59,我们在解码器中读到#59时,编译表的最大索引只有#58,#59所对应的字符串就等于#58所对应的字符串(也就是p[...])加上这个字符串的第一个字符(也就是p),也就是p[...]p。事实上,这种猜测法是很准确(有点不好理解,仔细想一想吧)。上面的解码过程用伪代码表示就像下面这样:

解码器伪代码

Initialize String Table;
[code] = First Code in the CodeStream;
Output the String for [code] to the CharStream;
[old] = [code];
[code] = Next Code in the CodeStream;
while ([code] != EOF )
{
  if ( [code] is in the StringTable)
  {
    Output the String for [code] to the CharStream; // 输出[code]所对应的字符串
    [...] = translation for [old]; // [old]所对应的字符串
    k = first character of translation for [code]; // [code]所对应的字符串的第一个字符
    add [...]k to the StringTable;
    [old] = [code]; 
  }
  else
  {
    [...] = translation for [old]; 
    k = first character of [...]; 
    Output [...]k to CharStream;
    add [...]k to the StringTable;
    [old] = [code]; 
  }
  [code] = Next Code in the CodeStream;
}

GIF数据压缩
~~~~~~~~~~~

下面是GIF文件的图象数据结构:

BYTE76543210BIT
1

编码长度

LZW Code Size - LZW压缩的编码长度,也就是要压缩的数据的位数
 ...数据块
 块大小数据块,如果需要可重复多次
 编码数据
 ...数据块
 块终结器一个图象的数据编码结束,固定值0

把光栅数据序列(数据流)压缩成GIF文件的图象数据(字符流)可以按下面的步骤进行:
1.定义编码长度
GIF图象数据的第一个字节就是编码长度(Code Size),这个值是指要表现一个像素所需要的最小位数,通常就等于图象的色深;
2.压缩数据
通过LZW压缩算法将图象的光栅数据流压缩成GIF的编码数据流。这里使用的LZW压缩算法是从标准的LZW压缩算法演变过来的,它们之间有如下的差别:
  [1]GIF文件定义了一个编码大小(Clear Code),这个值等于2的『编码长度』次方,在从新开始一个编译表(编译表溢出)时均须输出该值,解码器遇到该值时意味着要从新初始化一个编译表;
  [2]在一个图象的编码数据结束之前(也就是在块终结器的前面),需要输出一个Clear Code+1的值,解码器在遇到该值时就意味着GIF文件的一个图象数据流的结束;
  [3]第一个可用到的编译表索引值是Clear Code+2(从0到Clear Code-1是根索引,再上去两个不可使用,新的索引从Clare Code+2开始添加);
  [4]GIF输出的编码流是不定长的,每个编码的大小从Code Size + 1位到12位,编码的最大值就是4095(编译表需要定义的索引数就是4096),当编码所须的位数超过当前的位数时就把当前位数加1,这就需要在编码或解码时注意到编码长度的改变。
3.编译成字节序列
因为GIF输出的编码流是不定长的,这就需要把它们编译成固定的8-bit长度的字符流,编译顺序是从右往左。下面是一个具体例子:编译5位长度编码到8位字符

0bbbaaaaa
1dcccccbb
2eeeedddd
3ggfffffe
4hhhhhggg
 ...
N        

 
4.打包
  前面讲过,一个GIF的数据块的大小从0到255个字节,第一个字节是这个数据块的大小(字节数),这就需要将编译编后的码数据打包成一个或几个大小不大于255个字节的数据包。然后写入图象数据块中。


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值