TGA文件格式
简介
TGA(or TARGA)是由Truevision公司开发的一种描述bitmap(位图)图像文件格式,能表示黑白、索引颜色、RGB颜色等bitmap,是目前应用最广泛的图像格式. 文件扩展名.tga,兼顾bitmap的图像质量、JPEG的小体积特点,支持不失真的压缩算法(RLE).
TGA格式文件目前有2个版本v1.0和v2.0: v1.0称为origin Truevision TGA; v2.0称为new TGA File或extension TGA File.
new TGA File解决了以下需求(也是新增内容, 如果没用到, 可不必关心):
- The inclusion of a scaled-down “postage stamp” copy of the image 缩减版postage stamp图像副本
- Date and Time of image file creation 图像文件创建的日期和时间
- Author Name 作者名
- Author Comments 作者备注
- Job Name 作业名
- Job Accumulated Time 作业累计时间
- Gamma Value 伽马值
- Correct Color LUT
- Pixel Aspect Ratio 像素纵横比
- Scan Line Offset Table 扫描线偏移表
- Key Color 关键色
- Software Package Name and Version Number 软件包名和版本号
- Developer Definable Areas 开发商定义区域
- Attribute (Alpha) channel Type 属性(α)通道类型
- The ability for simple expansion 简单扩展能力
本文主要解析TGA v2.0格式(详见参考链接).
术语
Pseudo-Color(伪彩色): 将整个像素值用作可编程颜色表的单个索引, 该颜色表包含实际要显示的红、绿、蓝颜色强度. 使用这种图像的Truevision产品(硬件)有: VDA, VDA/D, TARGA M8, ATVista, NuVista和HR视频板.
True-Color(真彩): 每个像素的红、绿、蓝字段直接决定每种原色强度, 而非通过索引指向颜色表. 对应Truevision产品有: ICB, TARGA 16, TARGA 24, TARGA 32, ATVista和NuVista视频板.
Direct-Color(直接彩色): 每个像素分为红、绿、蓝字段, 但这些字段是单独的索引, 用来访问独立的可编程颜色查找表. 颜色表的查找结果决定了每个原色的强度. 直接彩色系统类似于伪彩色系统, 除了颜色表中的红、绿、蓝可单独改变(改单个索引或查找到的颜色值即可); 而伪彩色系统中的红、绿、蓝, 是绑定到一起存放在颜色表中的. 对应Truevision产品有: ATVista和NuVista视频板.
仅用作伪彩色设备: VDA, VDA/D, TARGA M8, HR;
仅用作真彩设备: ICB, TARGA 16, 24, 32.
Long = 32bit
Short = 16bit
Byte = 8bit
ASCII = C风格字符串, 多个字节, 以NUL byte结尾.
Bit Numbering(位序):
Byte Ordering(字节序): TGA采用Intel字节序(非Motorola字节序), 即低位字节优先. (tips: 解析跨字节整型数据时会用到, 如short, long类型)
TGA格式
TGA格式各主要组成部分及其分布, 如下图所示:
其中, 白底色模块为固定长度, 蓝底色部分表示可变长度(variable).
TGA头部(TGA Header)
18byte头部,包含5个域:
域编号(field no.) | 长度 | 域名 | 描述 |
---|---|---|---|
1 | 1byte | Id length | Image id段长度,取值0~255. 0表示无id段 |
2 | 1byte | Color map type | 是否包含颜色表(color map) 0: 不使用颜色表; 1: 使用颜色表 |
3 | 1byte | Image type | 图像类型. 应用场景详见后文Image Types章节. 0~127为Truevision公司用于一般应用, 128~255供开发者使用. 0: 没有图像数据; 1: 未压缩的颜色表图像; 2: 未压缩的TRUE-COLOR图像; 3: 未压缩的黑白图像; 9: RLE压缩的颜色表图像; 10: RLE压缩的TRUE-COLOR图像; 11: 压缩的黑白图像. |
4 | 5byte | Color map specification | 描述颜色表规格. 如果Header.Color map type = 0, 则没有颜色表存在, 这5byte应全为0. |
2byte | First Entry Index | 颜色表起点, 即颜色表第一项的索引 | |
2byte | Color map Length | 颜色表长度, 即颜色表共有多少项 | |
1byte | Color map Entry Size | 颜色表项大小, 即每个项占用bit数. 典型值15, 16, 24, 32. 即使是15, 每次也要用16bit解析, 然后忽略第16bit | |
5 | 10byte | Image specification | 描述图像维度和格式 |
2byte | X origin of Image | 图像起点(左下角)x坐标. 基于屏幕原点在左下角 | |
2byte | Y origin of Image | 图像起点(左下角)y坐标. 基于屏幕原点在左下角 | |
2byte | Image Width | 图像宽度(单位: pixel) | |
2byte | Image Height | 图像高度(单位: pixel) | |
1byte | Pixel Depth | 像素深度, 即每个像素的bit数, 包含属性或α通道. 常用值8, 16, 24, 32 | |
1byte | Image Descriptor | 图像描述器. bit3~0: 关联到每个像素的属性位数, 对于Targa 16, 应为0或1; 对于Targa 24, 应为0; 对于Targa 32, 应为8. 与Field 24有关. bit5~4: 指示传输像素数据到屏幕的的顺序. bit4从左到右顺序, bit5为从上到下顺序. bit7~6: 须为0, 兼容未来版本. |
图像/颜色表数据(Image/Color Map Data)
域编号(field no.) | 长度 | 域名 | 描述 |
---|---|---|---|
6 | 可变. 取决于Header.Id length(field 1)值 |
Image Id | 可选域. Header.Id length = 0表明无该段 |
7 | 可变. 取决于Header.Color map type(field 2)及Color map Length(field 4.2), Color map Entry Size(4.3) |
Color Map Data | 实际颜色表信息. field 2 = 0, 表明无color map存在; field = 1, 则长度为(field 4.2 * field 4.3)bits. 每个颜色表项(entry)用整数字节存储, 不会出现小数字节. 颜色表项的RGB颜色, 存放在多字节项的连续位段中. |
8 | 可变. |
Image Data | 图像数据信息. 包含Width × Height pixels, Width和Height在Field 5.6和5.5中定义. 每个像素都存储为整数字节. |
颜色表数据
根据颜色表规格(field 4)的字段, 知颜色表数据(Image Map Data, field 7)信息:
First Entry Index => 颜色表的第一项的索引;
Color map Length => 颜色表中项的数量;
Color map Entry Size => 颜色表中每一项的大小.
tips: 颜色表中, 每个元素称为一个颜色表项(Color Map Entry), 简称项(Entry).
问题1: 根据TGA格式各组成部分的排列,颜色表所在域Image Map Data紧跟Image ID, 前面的域都能确定大小, 为何还需要提供First Entry Index?
由于官方文档描述不清, 个人理解: 颜色表中存放着若干项, 但不一定都用到. 比如有1000个项, 但只用了其中72个(从342开始), 此时, 可设置First Entry Index = 342, Color map Length = 72.
问题2: 颜色表规格描述了颜色表位置、项数、每项大小, 但存放什么内容呢?
存放RGB颜色值, 但每个R、G、B分量占用空间不一定是1byte, 而是\(min(\frac{field 4.3}{3}, 8)\)bit, 即(Color map Entry Size)/3和8的最小值.
例如, Color map Entry Size指定项大小为8, 则每个R、G、B分量占2bit(多余高位忽略);
Color map Entry Size = 16, 则每个R、G、B分量占5bit;
Color map Entry Size = 24, 则每个R、G、B分量占8bit;
Color map Entry Size = 32, 则每个R、G、B分量占8bit;
图像数据
根据图像规格(field 5)的字段, 知图像数据(Image Data, field 8)信息:
Image Width => 图像宽度(pixel)
Image Height => 图像高度(pixel)
Pixel Depth => 每个像素的位数, 通常是8、16、24、32(其他值也能用).
问题3: Pixel存放什么?
根据不同的Image Type(详见后文), Pixel存放内容有不同的解读.
对于颜色表图像(COLOR-MAPPED), Image type(field 3)=1或9, Pixel存放的就是颜色表项的索引(基于前面的First Entry Index计算).
对于真彩图像(TRUE-COLOR), Image type(field 3)=2或10, Pixel存放的就是R、G、B值(由Image Descriptor决定属性位数, 即α通道).
对于黑白图像(BLACK and WHITE), Image type(field 3)=3或11, Pixel存放的就是灰度值(8bit即可).
Pixel通常会有下面几种类型:
from: TGA File Format Summary
开发者区域(Develop Area)
域编号(field no.) | 长度 | 域名 | 描述 |
---|---|---|---|
9 | 取决于开发者 | Develop Area | 可用于存储任何类型信息, 推荐用于存储应用程序特定信息(即不适用于其他产品、未被TGA格式涵盖的信息). 大小、格式取决于开发者. 普通读者可忽略这段内容, 除非了解具体格式信息. |
如果包含不止1个开发者区域,则创建一个开发者目录(Developer Directory)进行映射. Developer Directory由TGA File Footer(TGA脚注)的offset(field 29.2)指定位置.
扩展区域(EXTENSION AREA)
域编号(field no.) | 长度 | 域名 | 描述 |
---|---|---|---|
10~27 | 495byte 未来版本可能变化 |
Extension Area | 用于满足开发者额外文件信息的需求. 由TGA File Footer(TGA脚注)域中的Extension Area Offset(field 29.1)指定位置, 如果Offset = 0, 该域不存在; 否则, Offset表面从文件开始计算的该域位置 |
10 | 2byte | Extension Size | 扩展区域长度. 对于TGA v2.0, 该值为495. |
11 | 41byte | Author Name | 图像文件作者名. C风格字符串(ASCII编码), 须以NUL byte结尾. 如果没有用到, 必须都是NULL. |
12 | 324byte | Author Comments | 作者备注. 支持最多4行(每行80字符), 每行以NUL byte终结. |
13 | 12byte | Date/Time Stamp | 图像保存时的日期、时间戳, 由6个SHORT数组成. SHORT 0: 月份(1-12); SHORT1: 日(1-31); SHORT2: 年(4个数字, 如2024); SHORT3: 时(0-23); SHORT4: 分(0-59); SHORT5: 秒(0-59). 文件本身日期可能会被操作系统修改, 该段避免了这点. 如果未使用, 0填充. |
14 | 41byte | Job Name/ID | 作业名/ID. C风格字符串, 须以NUL byte结尾. 如果未使用, 可用NUL byte或space填充(非结尾部分). |
15 | 6byte | Job Time | 图像保存时作业运行时间, 由3个SHORT值组成: SHORT 0: 时(0-65535); SHORT 1: 分(0-59); SHORT 2: 秒(0-59). 如未使用, 0填充. |
16 | 41byte | Software ID | 软件ID, C风格字符串. |
17 | 3byte | Software Version | 软件版本, C风格字符串. SHORT(byte0~1): 版本号*100; BYTE(byte 2): 版本字母. e.g 版本号4.17b, 对应SHORT=417, BYTE='b'. 如未使用, SHORT=0b0, BYTE=space |
18 | 4byte | Key Color | 图像保存时的关键颜色, 可认为是"背景颜色"或"透明颜色". 格式: A:R:G:B, 其中A(最高字节)是α通道. 如未使用, 设置为0. |
19 | 4byte | Pixel Aspect Ratio | 像素纵横比. SHORT 0: 分子(像素宽); SHORT 1: 分母(像素高). 如果都设为相同非0值, 则图像用方形像素组成; 分母为0表示未指定. |
20 | 4byte | Gamma Value | gamma值分数形式. SHORT 0: gamma分子; SHORT 1: gamma分母. 结果值应在0~10.0, 精度1位小数. 未校正的图像结果值应为1.0. 分母设为0, 表示未使用gamma段. |
21~27 | 这部分不常用到, 略. |
TGA文件脚注(TGA FILE FOOTER)
解析TGA文件时,如何判定是Origin TGA格式(v1.0)还是New TGA格式(v2.0)?
可读取TGA文件的最后26byte脚注来实现.
合法的脚注,byte8~23为签名"TRUEVISION-XFILE". 如果检测到签名,则为New TGA,说明包含Develop Area, Extension Area;否则,为Origin TGA.
Byte 0-3: The Extension Area Offset 扩展区域位置由该值决定;
Bytes 4-7: The Developer Directory Offset 见下文;
Bytes 8-23: The Signature 签名, 用于判定是否为NEW TGA
Byte 24: ASCII Character “.” NEW TGA固定值
Byte 25: Binary zero string terminator (0x00) 固定值
注意:不要求开发者读写、使用Extension或Develop Area,这些是可选的. 但推荐文件包含TGA File Footer.
域编号(field no.) | 长度 | 域名 | 描述 |
---|---|---|---|
28 | 4byte | Extension Area Offset | Extension Area的offset值, 从文件开头开始算, 可用seek()函数定位. 0表示无Extension Area. |
29 | 4byte | Developer Directory Offset | Developer Directory的offset值. 0表示无Developer Directory Area. |
30 | 16byte | Signature | 签名, NEW TGA是"TRUEVISION-XFILE" |
31 | 1byte | Reserved Character | 保留. 须为".", 否则不认为是正确的TGA文件 |
32 | 1byte | Binary Zero String Terminator | 二进制0终结符. TGA脚注可解读为C风格字符串. |
图像类型(Image Type)
解读由Field 2(Color Map Type)和Field 3(Image Type)决定的图像类型,方便判断什么时候该用什么类型.
1: 颜色表图像类型
用于存储颜色表图像,如VDA/D,TARGA M8或颜色表TrueVista图像. 该格式能快速获取、显示,但会耗费较多存储空间. 适用于存储和显示时间很关键,但文件大小不重要的情形.
文件格式要求:Color Map Type = 0x01, Image Type = 0x01.
2: 真彩图像
用于存储图像,其中每个像素都由红、绿、蓝表示(例如,ICB、TARGA 16、TARGA 24、TARGA 32、 TrueVISTA图像). 适用于存储和显示时间非常重要,但文件大小不重要的情形.
文件格式要求:Color Map Type = 0x01, Image Type = 0x02.
3: 黑白无颜色表图像
用于存储光栅图像,其中每个像素由灰度值表示(如TARGA 8, M8及一些TrueVista模式).
文件格式要求:Color Map Type = 0x00, Image Type = 0x03.
9: RLE压缩的颜色表图像
用于存储每个像素都由颜色表索引表示的图像.RLE算法压缩图像,节约大量存储空间.
文件格式要求:Color Map Type = 0x01, Image Type = 0x09.
10: RLE压缩的真彩图像
用于存储光栅图像,其中每个像素由红、绿、蓝表示. RLE算法压缩图像. 该格式用于存储ICB、TARGA 16/24/32、TrueVISTA(16bit RGB, 32bit RGB模式)图像. 适用于由计算机生成的图像,包含大段相同颜色.
文件格式要求:Color Map Type = 0x00, Image Type = 0x0A.
11: RLE压缩的黑白图像
用于存储光栅图像,其中每个像素由灰度值表示. RLE压缩图像. 用于存储黑白TARGE 8/M8,及计算机生成的包含大段相同颜色的图像.
文件格式要求:Color Map Type = 0x00, Image Type = 0x0B.
RLE编码算法
RLE(run-length encoding),即游程编码、行程编码,是一种无损文件压缩算法. 图像数据类型9、10用到了RLE压缩图像.
RLE算法思想:连续相同的数值,用 重复数 + 数值 表示. 例如,文本文件中,原始字符串"AABCCC",经RLE编码后,变成"2A1B3C".
对于图像文件,用RLE算法对图像数据(Image Data)进行编码,所得图像称为RLE图像. 其中,包含2类数据元素:RLE packet、Raw packet.
packet格式
每个packet的第1个byte,称为Repetition Count field(重复数字段). 第2个byte,称为Pixel Value field(像素值字段).
packet格式如下图所示:
- packet类型(packet type)
第1个byte的bit7(最高位):
1 - 表明该packet是RLE packet;
0 - Raw packet.
- 重复数(Repetition Count)
指明后面Pixel Value重复的次数,范围0~127.
注意:实际重复次数 = Repetition Count + 1,即值0表示重复次数1,1表示重复次数2,...,127表示重复次数128.
- Pixel Value
对于RLE packet, 会合并连续相同的像素,用1个Pixel Value表示这些连续的像素,而Repetition Count对连续相同像素进行计数;
对于Raw packet,不会进行合并,像素原来是怎么存储的,现在依然不变,但Repetition Count会对这些连续相同的像素计数.
例如,扫描到图像的一行有128个连续相同的像素,每个像素有24bit(3byte). 现用RLE算法进行压缩. 需要多少存储空间?
如果用Raw packet,那么需要3byte * 128 = 384byte,再加上1byte Repitition Count,总计385byte;
如果用RLE packet,那么需要3byte表示重复像素,再加上1byte Repitition Count,总计4byte.
也就是说,Raw packet并不会减少图像存储空间,相反,会增加存储空间.
关于跨行
对于RLE packet,编码像素时,即使行尾与下一行头像素相同,绝不应该跨行. 应该怎么做?
编码为独立的packet,而不是同一个. 因为这样,软件能用扫描线快速随机访问每行.