一、实验原理——TGA文件格式
根据不同内容将其大致分为四个部分:
- TGA文件头(TgaHeader)
名称 | 字节数 | 解释 |
---|---|---|
图像信息字段(ID length) | 1 | 指出图像信息字段长度:0~255 |
颜色表类型(Color Map Type) | 1 | 0:无颜色表;1:有颜色表 |
图像类型码(Image Type) | 1 | 图像格式 |
- 颜色表信息字段(TgaHeader_CM)
名称 | 字节数 | 解释 |
---|---|---|
颜色表首址(First Entry Index) | 2 | 颜色表首的入口索引,整型 |
颜色表长度(Color map Length) | 2 | 整型 |
颜色表项位数(Color map Entry Size) | 1 | 15、16、24或者32位 |
- 图像规格字段(TgaHeader_Info)
名称 | 字节数 | 解释 |
---|---|---|
图像X位置的起始位置(X-origin of Image) | 2 | 图像左下角的水平坐标,整型 |
图像Y位置的起始位置(Y-origin of Image) | 2 | 图像左下角的垂直坐标,整型 |
图像宽度(Image Width) | 2 | 以像素为单位,图像宽度的整型(低位-高位) |
图像高度(Image Height) | 2 | |
像素深度(Pixel Depth) | 1 | 表示每个像素占用的位数,通常8/16/24/32位 |
图像描述符(Image Descriptor) | 1 | bit0-3:每像素对应属性位的位数,TGA16:0或1,TGA24:0,TGA32:8; bit4:0; bit5:屏幕起始位置标志,0:原点在左下角,1:原点在左上角,对于真彩图像值一定为0; bit6-7:交叉数据存储标志 |
- 图像/颜色表数据(Image/Color Map Data)
名称 | 字节数 | 解释 |
---|---|---|
图像信息字段(Image ID) | 可变长 | 存储了图像的身份信息(Identifying Information)这个字段最长为255个字节,图像信息字段长度字段规定了它的长度。 |
颜色表数据(Color Map Data) | 可变长 | 这个变长字段包含了颜色表信息(LUT数据),颜色表表项大小和颜色表长度字段共同规定了颜色表数据的长度。每个颜色表表项用整数个字节存储,规定每个颜色表的RGB采用连续的位存储,每个颜色的位长为MIN(颜色表表项大小字段值/3,8)。 |
图像数据(Image Data | 可变长 | 这个字段包含Width*Height个像素,每个像素的格式如下所示: (1)用伪彩色表示,则是一个颜色图的一个索引号; (2)真彩图,则是属性,红绿,蓝顺序的数据; (3)用调配色表示,就是独立的颜色表索引。 |
二、主要功能模块分析
1、TGA文件结构体定义
typedef struct TgaHeader
{
BYTE IDLENGTH;//图像信息字段
BYTE COLORMAPTYPE;//颜色表类型
BYTE IMAGETYPE;//图像类型码
}TGAHEAD;
typedef struct TgaHeader_CM
{
WORD CMENTRY;//颜色表首址
WORD CMLENGTH;//颜色表长度
BYTE CMSIZE;//颜色表项位数
}TGA_cm_header;
typedef struct TgaHeader_Info
{
WORD XSTART;//图像X坐标起始位置
WORD YSTART;//图像Y坐标起始位置
WORD IMAGEWIDTH;//图像宽度
WORD IMAGEHEIGHT;//图像高度
BYTE PIXEDEPTH;//像素深度
BYTE IMAGEDESCRIPTOR;//图像描述字节
}TGA_Info_header;
- 注意结构体对齐的问题:
- 在实际中,存储变量时地址要求对齐,编译器在编译程序时会遵循两条原则:
(1)结构体变量中成员的偏移量必须是成员大小的整数倍;
(2)结构体大小必须是所有成员大小的整数倍。 - 对于偏移量不是自身大小整数倍的成员,编译器会在前一个成员后补充空字节。
对于大小不是所有成员变量整数倍的,编译器会自动在最后一个成员补充空字节。 - 由此会导致结构体之后的数据读取错误。
故需要以颜色表首地址为结构体首地址再开辟一个结构体。
2、定义TGA文件头并读入
//定义
TGAHEAD File_header;
TGA_cm_header cm_header;
TGA_Info_header Info_header;
//读入
tgaFile.read((char*)(&File_header), 3);
tgaFile.read((char*)(&cm_header), 5);
tgaFile.read((char*)(&Info_header), 10);
3、判断图像格式
(1)判断图像格式属于真彩还是伪彩
- 若为真彩,直接读取RGB数据
- 若为伪彩,先读入颜色表,再读入图像数据,根据像素数值查找RGB强度
(2)判断是否存在图像信息字段
- 若结构体TgaHeader中的IDLength值为0,则不存在图像描述信息字段
- 若值不为0,则IDLength字段大小则为图像描述信息字段大小。
if (File_header.IMAGETYPE == 1)
{
cout << "未压缩的颜色表图像" << endl;
cout << "颜色表长度:" << int(cm_header.CMLENGTH) << endl;
cout << "颜色表项位数:" << int(cm_header.CMSIZE) << endl;
cout << "像素深度:" << int(Info_header.PIXEDEPTH) << endl;
if (File_header.IDLENGTH == 0)
cout << "无图像信息字段" << endl;
else
{
int imagelength = File_header.IDLENGTH;
cout << "图像信息字段长度为" << imagelength << endl;
}
//在此处读入图像信息数据
}
else if (File_header.IMAGETYPE == 2)
{
cout << "未压缩的真彩色图像" << endl;
if (File_header.IDLENGTH == 0)
{
cout << "无图像信息字段" << endl;
//在此处读入图像信息数据
}
else
{
int imagelength = File_header.IDLENGTH;
cout << "图像信息字段长度为" << imagelength << endl;
//在此处读入图像信息数据
}
}
else
{
cout << "其他图像类型" << endl;
return 0;
}