请用c++代码编写一个程序,把tga图片的存储tga格式转换器为png的存储格式

61801人阅读
C/C++(35)
通过我这些天用C++读写bmp图像的经历,摸索再摸索,终于对bmp文件的结构、操作有了一定的了解,下面就大概介绍bmp图片纯C++的读取、旋转和保存的实现过程。
要用C++读取bmp图片文件,首先要弄清楚bmp格式图片文件的结构。可以参考这篇文章:
有几点需要注意的是:
在读取bmp图片的时候,一定要注意内存对齐的问题,譬如文件头,否则无法读取出正确结果。
关于图片的像素数据,每一行的像素的字节数必须是4的整数倍。如果不是,则需要补齐。一般来说,bmp图像文件的数据是从下到上,从左到右的。即从文件中最先读到的是图像最下面一行的左边第一个像素,然后是坐标第二个.....接下来是倒数第二行的第一个像素。
采用的编译环境是VS2008。
关于图像旋转,并不难。只需要搞清楚像素坐标变换公式就行。我以图像的中心点为坐标原点。先把像素在目标图像中的位置变化为坐标系中的位置,做旋转变换求出变换之前的在坐标系中的坐标,再变换为在图片中的位置。
公式:(x1,y1)是变换之前的坐标系中的坐标,(x2,y2)是变换之后的坐标系中的坐标。angle为逆时针旋转的角度数。
x1 = cos(angle)*x2-sin(angle)*y2;
y1 = sin(angle)*x2-cos(angle)*y2;
我的代码分为两个版本:灰度图的和彩色图的。
灰度图是只含亮度信息,不含彩色信息的图像。bmp格式文件中并没有灰度图这个概念,但是我们很容易地用bmp文件来表示灰度图。方法是用256色的调色板,只不过这个调色板有点特殊,每一项的RGB值都是相同的,从(0,0,0),(1,1,1),...,一直到(255,255,255)。这样,灰度图就可以用256色图来表示了。其图像数据就是调色板索引值,也就是实际的RGB的亮度值。另外因为是256色的调色板,所以图像数据中的一个字节代表一个像素。如果是彩色的256色图,图像处理后可能会产生不属于这256色的颜色,所以,图像处理一般采用灰度图。这也可以更好地将重点放在算法上。
下面是灰度图旋转代码,能处理任意尺寸的bmp灰度图,以及旋转任意角度(逆时针)。
代码包括两个文件:BmpRot.h和BmpRot.cpp
BmpRot.h:
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef long LONG;
//位图文件头定义;
//其中不包含文件类型信息(由于结构体的内存结构决定,
//要是加了的话将不能正确读取文件信息)
typedef struct
tagBITMAPFILEHEADER{
//WORD bfT//文件类型,必须是0x424D,即字符“BM”
DWORD bfS//文件大小
WORD bfReserved1;//保留字
WORD bfReserved2;//保留字
DWORD bfOffB//从文件头到实际位图数据的偏移字节数
}BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER{
DWORD biS//信息头大小
LONG biW//图像宽度
LONG biH//图像高度
WORD biP//位平面数,必须为1
WORD biBitC//每像素位数
biC //压缩类型
biSizeI //压缩图像大小字节数
biXPelsPerM //水平分辨率
biYPelsPerM //垂直分辨率
biClrU //位图实际用到的色彩数
biClrI //本位图中重要的色彩数
}BITMAPINFOHEADER; //位图信息头定义
typedef struct tagRGBQUAD{
BYTE rgbB //该颜色的蓝色分量
BYTE rgbG //该颜色的绿色分量
BYTE rgbR //该颜色的红色分量
BYTE rgbR //保留值
}RGBQUAD;//调色板定义
//像素信息
typedef struct tagIMAGEDATA
}IMAGEDATA;BmpRot.cpp:
#include &stdio.h&
#include &BmpRot.h&
#include &stdlib.h&
#include &math.h&
#include &iostream&
#define PI 3.14159//圆周率宏定义
#define LENGTH_NAME_BMP 30//bmp图片文件名的最大长度
//变量定义
BITMAPFILEHEADER strH
RGBQUAD strPla[256];//256色调色板
BITMAPINFOHEADER strI
//显示位图文件头信息
void showBmpHead(BITMAPFILEHEADER pBmpHead){
cout&&&位图文件头:&&&
cout&&&文件大小:&&&pBmpHead.bfSize&&
cout&&&保留字_1:&&&pBmpHead.bfReserved1&&
cout&&&保留字_2:&&&pBmpHead.bfReserved2&&
cout&&&实际位图数据的偏移字节数:&&&pBmpHead.bfOffBits&&endl&&
void showBmpInforHead(tagBITMAPINFOHEADER pBmpInforHead){
cout&&&位图信息头:&&&
cout&&&结构体的长度:&&&pBmpInforHead.biSize&&
cout&&&位图宽:&&&pBmpInforHead.biWidth&&
cout&&&位图高:&&&pBmpInforHead.biHeight&&
cout&&&biPlanes平面数:&&&pBmpInforHead.biPlanes&&
cout&&&biBitCount采用颜色位数:&&&pBmpInforHead.biBitCount&&
cout&&&压缩方式:&&&pBmpInforHead.biCompression&&
cout&&&biSizeImage实际位图数据占用的字节数:&&&pBmpInforHead.biSizeImage&&
cout&&&X方向分辨率:&&&pBmpInforHead.biXPelsPerMeter&&
cout&&&Y方向分辨率:&&&pBmpInforHead.biYPelsPerMeter&&
cout&&&使用的颜色数:&&&pBmpInforHead.biClrUsed&&
cout&&&重要颜色数:&&&pBmpInforHead.biClrImportant&&
int main(){
char strFile[LENGTH_NAME_BMP];//bmp文件名
IMAGEDATA *imagedata = NULL;//动态分配存储原图片的像素信息的二维数组
IMAGEDATA *imagedataRot = NULL;//动态分配存储旋转后的图片的像素信息的二维数组
int width,//图片的宽度和高度
cout&&&请输入所要读取的文件名:&&&
FILE *fpi,*
fpi=fopen(strFile,&rb&);
if(fpi != NULL){
//先读取文件类型
fread(&bfType,1,sizeof(WORD),fpi);
if(0x4d42!=bfType)
cout&&&the file is not a bmp file!&&&
return NULL;
//读取bmp文件的文件头和信息头
fread(&strHead,1,sizeof(tagBITMAPFILEHEADER),fpi);
//showBmpHead(strHead);//显示文件头
fread(&strInfo,1,sizeof(tagBITMAPINFOHEADER),fpi);
//showBmpInforHead(strInfo);//显示文件信息头
//读取调色板
for(unsigned int nCounti=0;nCounti&strInfo.biClrUnCounti++)
fread((char *)&(strPla[nCounti].rgbBlue),1,sizeof(BYTE),fpi);
fread((char *)&(strPla[nCounti].rgbGreen),1,sizeof(BYTE),fpi);
fread((char *)&(strPla[nCounti].rgbRed),1,sizeof(BYTE),fpi);
fread((char *)&(strPla[nCounti].rgbReserved),1,sizeof(BYTE),fpi);
width = strInfo.biW
height = strInfo.biH
//图像每一行的字节数必须是4的整数倍
width = (width * sizeof(IMAGEDATA) + 3) / 4 * 4;
//imagedata = (IMAGEDATA*)malloc(width * height * sizeof(IMAGEDATA));
imagedata = (IMAGEDATA*)malloc(width * height);
imagedataRot = (IMAGEDATA*)malloc(2 * width * 2 * height * sizeof(IMAGEDATA));
//初始化原始图片的像素数组
for(int i = 0;i &++i)
for(int j = 0;j &++j)
(*(imagedata + i * width + j)).blue = 0;
//(*(imagedata + i * width + j)).green = 0;
//(*(imagedata + i *
width + j)).red = 0;
//初始化旋转后图片的像素数组
for(int i = 0;i & 2 *++i)
for(int j = 0;j & 2 *++j)
(*(imagedataRot + i * 2 * width + j)).blue = 0;
//(*(imagedataRot + i * 2 * width + j)).green = 0;
//(*(imagedataRot + i * 2 * width + j)).red = 0;
//fseek(fpi,54,SEEK_SET);
//读出图片的像素数据
fread(imagedata,sizeof(struct tagIMAGEDATA) * width,height,fpi);
fclose(fpi);
cout&&&file open error!&&&
return NULL;
//图片旋转处理
int RotateA//要旋转的角度数
//要旋转的弧度数
int midX_pre,midY_pre,midX_aft,midY_//旋转所围绕的中心点的坐标
midX_pre = width / 2;
midY_pre = height / 2;
midX_aft =
midY_aft =
int pre_i,pre_j,after_i,after_j;//旋转前后对应的像素点坐标
cout&&&输入要旋转的角度(0度到360度,逆时针旋转):&&&
cin&&RotateA
angle = 1.0 * RotateAngle * PI / 180;
for(int i = 0;i & 2 *++i)
for(int j = 0;j & 2 *++j)
after_i = i - midX_//坐标变换
after_j = j - midY_
pre_i = (int)(cos((double)angle) * after_i - sin((double)angle) * after_j) + midX_
pre_j = (int)(sin((double)angle) * after_i + cos((double)angle) * after_j) + midY_
if(pre_i &= 0 && pre_i & height && pre_j &= 0 && pre_j & width)//在原图范围内
*(imagedataRot + i * 2 * width + j) = *(imagedata + pre_i * width + pre_j);
//保存bmp图片
if((fpw=fopen(&b.bmp&,&wb&))==NULL)
cout&&&create the bmp file error!&&&
return NULL;
WORD bfType_w=0x4d42;
fwrite(&bfType_w,1,sizeof(WORD),fpw);
//fpw +=2;
fwrite(&strHead,1,sizeof(tagBITMAPFILEHEADER),fpw);
strInfo.biWidth = 2 *
strInfo.biHeight = 2 *
fwrite(&strInfo,1,sizeof(tagBITMAPINFOHEADER),fpw);
//保存调色板数据
for(unsigned int nCounti=0;nCounti&strInfo.biClrUnCounti++)
fwrite(&strPla[nCounti].rgbBlue,1,sizeof(BYTE),fpw);
fwrite(&strPla[nCounti].rgbGreen,1,sizeof(BYTE),fpw);
fwrite(&strPla[nCounti].rgbRed,1,sizeof(BYTE),fpw);
fwrite(&strPla[nCounti].rgbReserved,1,sizeof(BYTE),fpw);
//保存像素数据
for(int i =0;i & 2 *++i)
for(int j = 0;j & 2 *++j)
fwrite( &((*(imagedataRot + i * 2 * width + j)).blue),1,sizeof(BYTE),fpw);
//fwrite( &((*(imagedataRot + i * 2 * width + j)).green),1,sizeof(BYTE),fpw);
//fwrite( &((*(imagedataRot + i * 2 * width + j)).red),1,sizeof(BYTE),fpw);
fclose(fpw);
//释放内存
delete[] imagedataR
数据测试:
旋转前和旋转后的对比(45度):
彩色图的处理和灰度图略有不一样。主要是像素数据不同。由于每行数据的字节数必须是4的整数倍,这个地方处理起来要比灰度图麻烦很多,多以暂时还 没做好。本程序的局限性就是只能处理尺寸是4的整数倍的图片,可以旋转任意角度(逆时针)。
参考代码:分两个文件:BmpRot.h和BmpRot.cpp
BmpRot.h:
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef long LONG;
//位图文件头定义;
//其中不包含文件类型信息(由于结构体的内存结构决定,
//要是加了的话将不能正确读取文件信息)
typedef struct
tagBITMAPFILEHEADER{
//WORD bfT//文件类型,必须是0x424D,即字符“BM”
DWORD bfS//文件大小
WORD bfReserved1;//保留字
WORD bfReserved2;//保留字
DWORD bfOffB//从文件头到实际位图数据的偏移字节数
}BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER{
DWORD biS//信息头大小
LONG biW//图像宽度
LONG biH//图像高度
WORD biP//位平面数,必须为1
WORD biBitC//每像素位数
biC //压缩类型
biSizeI //压缩图像大小字节数
biXPelsPerM //水平分辨率
biYPelsPerM //垂直分辨率
biClrU //位图实际用到的色彩数
biClrI //本位图中重要的色彩数
}BITMAPINFOHEADER; //位图信息头定义
typedef struct tagRGBQUAD{
BYTE rgbB //该颜色的蓝色分量
BYTE rgbG //该颜色的绿色分量
BYTE rgbR //该颜色的红色分量
BYTE rgbR //保留值
}RGBQUAD;//调色板定义
//像素信息
typedef struct tagIMAGEDATA
}IMAGEDATA;
BmpRot.cpp:
#include &stdio.h&
#include &BmpRot.h&
#include &stdlib.h&
#include &math.h&
#include &iostream&
#define PI 3.14159//圆周率宏定义
#define LENGTH_NAME_BMP 30//bmp图片文件名的最大长度
//变量定义
BITMAPFILEHEADER strH
RGBQUAD strPla[256];//256色调色板
BITMAPINFOHEADER strI
//显示位图文件头信息
void showBmpHead(BITMAPFILEHEADER pBmpHead){
cout&&&位图文件头:&&&
cout&&&文件大小:&&&pBmpHead.bfSize&&
cout&&&保留字_1:&&&pBmpHead.bfReserved1&&
cout&&&保留字_2:&&&pBmpHead.bfReserved2&&
cout&&&实际位图数据的偏移字节数:&&&pBmpHead.bfOffBits&&endl&&
void showBmpInforHead(tagBITMAPINFOHEADER pBmpInforHead){
cout&&&位图信息头:&&&
cout&&&结构体的长度:&&&pBmpInforHead.biSize&&
cout&&&位图宽:&&&pBmpInforHead.biWidth&&
cout&&&位图高:&&&pBmpInforHead.biHeight&&
cout&&&biPlanes平面数:&&&pBmpInforHead.biPlanes&&
cout&&&biBitCount采用颜色位数:&&&pBmpInforHead.biBitCount&&
cout&&&压缩方式:&&&pBmpInforHead.biCompression&&
cout&&&biSizeImage实际位图数据占用的字节数:&&&pBmpInforHead.biSizeImage&&
cout&&&X方向分辨率:&&&pBmpInforHead.biXPelsPerMeter&&
cout&&&Y方向分辨率:&&&pBmpInforHead.biYPelsPerMeter&&
cout&&&使用的颜色数:&&&pBmpInforHead.biClrUsed&&
cout&&&重要颜色数:&&&pBmpInforHead.biClrImportant&&
int main(){
char strFile[LENGTH_NAME_BMP];//bmp文件名
IMAGEDATA *imagedata = NULL;//动态分配存储原图片的像素信息的二维数组
IMAGEDATA *imagedataRot = NULL;//动态分配存储旋转后的图片的像素信息的二维数组
int width,//图片的宽度和高度
cout&&&请输入所要读取的文件名:&&&
FILE *fpi,*
fpi=fopen(strFile,&rb&);
if(fpi != NULL){
//先读取文件类型
fread(&bfType,1,sizeof(WORD),fpi);
if(0x4d42!=bfType)
cout&&&the file is not a bmp file!&&&
return NULL;
//读取bmp文件的文件头和信息头
fread(&strHead,1,sizeof(tagBITMAPFILEHEADER),fpi);
//showBmpHead(strHead);//显示文件头
fread(&strInfo,1,sizeof(tagBITMAPINFOHEADER),fpi);
//showBmpInforHead(strInfo);//显示文件信息头
//读取调色板
for(unsigned int nCounti=0;nCounti&strInfo.biClrUnCounti++)
//存储的时候,一般去掉保留字rgbReserved
fread((char *)&strPla[nCounti].rgbBlue,1,sizeof(BYTE),fpi);
fread((char *)&strPla[nCounti].rgbGreen,1,sizeof(BYTE),fpi);
fread((char *)&strPla[nCounti].rgbRed,1,sizeof(BYTE),fpi);
cout&&&strPla[nCounti].rgbBlue&&&strPla[nCounti].rgbBlue&&
cout&&&strPla[nCounti].rgbGreen&&&strPla[nCounti].rgbGreen&&
cout&&&strPla[nCounti].rgbRed&&&strPla[nCounti].rgbRed&&
width = strInfo.biW
height = strInfo.biH
imagedata = (IMAGEDATA*)malloc(width * height * sizeof(IMAGEDATA));
imagedataRot = (IMAGEDATA*)malloc(2 * width * 2 * height * sizeof(IMAGEDATA));
//初始化原始图片的像素数组
for(int i = 0;i &++i)
for(int j = 0;j &++j)
(*(imagedata + i * width + j)).blue = 0;
(*(imagedata + i * width + j)).green = 0;
(*(imagedata + i *
width + j)).red = 0;
//初始化旋转后图片的像素数组
for(int i = 0;i & 2 *++i)
for(int j = 0;j & 2 *++j)
(*(imagedataRot + i * 2 * width + j)).blue = 0;
(*(imagedataRot + i * 2 * width + j)).green = 0;
(*(imagedataRot + i * 2 * width + j)).red = 0;
//fseek(fpi,54,SEEK_SET);
//读出图片的像素数据
fread(imagedata,sizeof(struct tagIMAGEDATA) * width,height,fpi);
for(int i = 0;i &++i)
fread(imagedata + i * width * sizeof(IMAGEDATA),sizeof(struct tagIMAGEDATA) * width,height,fpi);
fclose(fpi);
cout&&&file open error!&&&
return NULL;
//图片旋转处理
int RotateA//要旋转的角度数
//要旋转的弧度数
int midX_pre,midY_pre,midX_aft,midY_//旋转所围绕的中心点的坐标
midX_pre = width / 2;
midY_pre = height / 2;
midX_aft =
midY_aft =
int pre_i,pre_j,after_i,after_j;//旋转前后对应的像素点坐标
cout&&&输入要旋转的角度(0度到360度,逆时针旋转):&&&
cin&&RotateA
angle = 1.0 * RotateAngle * PI / 180;
for(int i = 0;i & 2 *++i)
for(int j = 0;j & 2 *++j)
after_i = i - midY_//坐标变换
after_j = j - midX_
pre_i = (int)(cos((double)angle) * after_i - sin((double)angle) * after_j) + midY_
pre_j = (int)(sin((double)angle) * after_i + cos((double)angle) * after_j) + midX_
if(pre_i &= 0 && pre_i & height && pre_j &= 0 && pre_j & width)//在原图范围内
*(imagedataRot + i * 2 * width + j) = *(imagedata + pre_i * width + pre_j);
//保存bmp图片
if((fpw=fopen(&b.bmp&,&wb&))==NULL)
cout&&&create the bmp file error!&&&
return NULL;
WORD bfType_w=0x4d42;
fwrite(&bfType_w,1,sizeof(WORD),fpw);
//fpw +=2;
fwrite(&strHead,1,sizeof(tagBITMAPFILEHEADER),fpw);
strInfo.biWidth = 2 *
strInfo.biHeight = 2 *
fwrite(&strInfo,1,sizeof(tagBITMAPINFOHEADER),fpw);
//保存调色板数据
for(unsigned int nCounti=0;nCounti&strInfo.biClrUnCounti++)
fwrite(&strPla[nCounti].rgbBlue,1,sizeof(BYTE),fpw);
fwrite(&strPla[nCounti].rgbGreen,1,sizeof(BYTE),fpw);
fwrite(&strPla[nCounti].rgbRed,1,sizeof(BYTE),fpw);
//保存像素数据
for(int i =0;i & 2 *++i)
for(int j = 0;j & 2 *++j)
fwrite( &(*(imagedataRot + i * 2 * width + j)).red,1,sizeof(BYTE),fpw);//注意三条语句的顺序:否则颜色会发生变化
fwrite( &(*(imagedataRot + i * 2 * width + j)).green,1,sizeof(BYTE),fpw);
fwrite( &(*(imagedataRot + i * 2 * width + j)).blue,1,sizeof(BYTE),fpw);
fclose(fpw);
//释放内存
delete[] imagedataR
数据测试:(旋转10°)
注意:颜色问题已解决。请看代码中注释部分。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1416909次
积分:12985
积分:12985
排名:第795名
原创:122篇
转载:15篇
评论:896条
文章:15篇
阅读:223726
(1)(1)(2)(1)(6)(2)(14)(4)(3)(7)(5)(7)(3)(2)(2)(3)(1)(5)(3)(8)(4)(5)(1)(8)(7)(5)(3)(3)(3)(3)(10)(4)(4)(3)
博客已迁移至:http://xiajunhust.github.io/下次自动登录
现在的位置:
& 综合 & 正文
Tga图片格式分析以及程序实现
本文转自本人Blog:
继位图之后,我们来看看图片的格式,以及程序实现。
常见的格式有非压缩和压缩两种格式,其他格式的我们在这里不做讲述。文件的第三个位作为标记:为非压缩格式,为压缩格式。它们的具体格式如下:
非压缩格式
图片类型:非压缩格式
图像信息字段长度
本字段是字节无符号整型,指出图像信息字段(见本子表的后面)长度,其取值范围是到,当它为时表示没有图像的信息字段。
颜色表类型
表示没有颜色表,表示颜色表存在。由于本格式是无颜色表的,因此此项通常被忽略。
图像类型码
该字段总为,这也是此类型为格式的原因。
颜色表规格字段
颜色表首址
颜色表首的入口索引,整型(低位-高位)
如果颜色表字段为,则忽略该字段
颜色表的长度
颜色表的表项总数,整型(低位高位)
颜色表项位数
位数(),代表位,代表位,代表位
图像规格字段
图像坐标起始位置
图像左下角坐标的整型(低位高位)值
图像坐标起始位置
图像左下角坐标的整型(低位高位)值
以像素为单位,图像宽度的整型(低位高位)
以像素为单位,图像宽度的整型(低位高位)
图像每像素存储占用位数
它的值为,或等等。决定了该图像是,等等。
图像描述符字节
每像素对应的属性位的位数;
对于,该值为或,对于,该值为,对于,该值为。
保留,必须为
屏幕起始位置标志
原点在左下角
原点在左上角
对于图像必须为
交叉数据存储标志
两路奇偶交叉
图像信息字段
包含一个自由格式的,长度是图像由“图像信息字段”指定。它常常被忽略(即偏移处值为),注意其最大可以含有个字符。如果需要存储更多信息,可以放在图像数据之后。
颜色表数据
如果颜色表类型为,则该域不存在,否则越过该域直接读取图像颜色表规格中描述了每项的字节数,为,,之一。
颜色数据,存放顺序为:
图片类型:压缩格式
图像信息字段长度
本字段是字节无符号整型,指出图像信息字段(见本子表的后面)长度,其取值范围是到,当它为时表示没有图像的信息字段。
颜色表类型
表示没有颜色表,表示颜色表存在。由于本格式是无颜色表的,因此此项通常被忽略。
图像类型码
该字段总为,这也是此类型为格式的原因。
颜色表规格字段
颜色表首址
颜色表首的入口索引,整型(低位-高位)
如果颜色表字段为,则忽略该字段
颜色表的长度
颜色表的表项总数,整型(低位高位)
颜色表项位数
位数(),代表位,代表位,代表位
图像规格字段
图像坐标起始位置
图像左下角坐标的整型(低位高位)值
图像坐标起始位置
图像左下角坐标的整型(低位高位)值
以像素为单位,图像宽度的整型(低位高位)
以像素为单位,图像宽度的整型(低位高位)
图像每像素存储占用位数
它的值为,或等等。决定了该图像是,等等。
图像描述符字节
每像素对应的属性位的位数;
对于,该值为或,对于,该值为,对于,该值为。
保留,必须为
屏幕起始位置标志
原点在左下角
原点在左上角
对于图像必须为
交叉数据存储标志
两路奇偶交叉
图像信息字段
包含一个自由格式的,长度是图像由“图像信息字段”指定。它常常被忽略(即偏移处值为),注意其最大可以含有个字符。如果需要存储更多信息,可以放在图像数据之后。
颜色表数据
如果颜色表类型为,则该域不存在,否则越过该域直接读取图像颜色表规格中描述了每项的字节数,为,,之一。
采用压缩后的颜色数据。
的压缩采用了算法,算法的基本思想是将数据分为两大类:
:连续的不重复字节
:连续的重复字节
算法应用于格式的图片压缩中,则把数据分为:
:连续的不重复像素颜色值
:连续的重复像素颜色值
然后将数据按这两类数据分成若干长度不相等数据块,每个数据块的开始都是一个个字节长度的(在纯数据压缩中位个字节位),后面紧跟着数据块,如下。
(个字节)
每个的第一位作为标记:表示类颜色数据,表示类颜色数据。剩下的位意义如下:
对于类数据:表示有多少个像素的颜色值。取值,表示个像素,所以最多为个像素,块则为这些不重复的像素颜色值。
对于类数据:表示有多少个像素具有相同的颜色值。取值,表示个像素,所以最多为个像素,仅包含一个像素的颜色值,即为重复的那个颜色值。
关于的实现,可以参考本文后面的“程序实现”部分的代码。
好了,弄清楚了文件格式后,编写程序就不是个难事清了。为了读取方便,我定义了结构体来表示文件头:
文件头信息
获取图像规格信息
读取图片信息字段
读取图片数据
对于非压缩格式(),我们可以直接读取:
对于压缩格式(),我们要按照算法解码:
同位图一样,如果想把用于,需要做行对齐处理,而却文件里的数据是没有行对齐的,所以加载必须程序进行行对齐。行对齐的方法如下:
:计算图片行对齐前每行的字节数:
:计算行对齐后的字节数:
:如果=则不需要对齐
:否则在每行的后面添加-个字节,并以填充。
文件存储颜色数据的格式为,如果需要得到格式的数据(如中)需要做转换。
本文转自本人Blog:
继位图之后,我们来看看图片的格式,以及程序实现。
常见的格式有非压缩和压缩两种格式,其他格式的我们在这里不做讲述。文件的第三个位作为标记:为非压缩格式,为压缩格式。它们的具体格式如下:
非压缩格式
图片类型:非压缩格式
图像信息字段长度
本字段是字节无符号整型,指出图像信息字段(见本子表的后面)长度,其取值范围是到,当它为时表示没有图像的信息字段。
颜色表类型
表示没有颜色表,表示颜色表存在。由于本格式是无颜色表的,因此此项通常被忽略。
图像类型码
该字段总为,这也是此类型为格式的原因。
颜色表规格字段
颜色表首址
颜色表首的入口索引,整型(低位-高位)
如果颜色表字段为,则忽略该字段
颜色表的长度
颜色表的表项总数,整型(低位高位)
颜色表项位数
位数(),代表位,代表位,代表位
图像规格字段
图像坐标起始位置
图像左下角坐标的整型(低位高位)值
图像坐标起始位置
图像左下角坐标的整型(低位高位)值
以像素为单位,图像宽度的整型(低位高位)
以像素为单位,图像宽度的整型(低位高位)
图像每像素存储占用位数
它的值为,或等等。决定了该图像是,等等。
图像描述符字节
每像素对应的属性位的位数;
对于,该值为或,对于,该值为,对于,该值为。
保留,必须为
屏幕起始位置标志
原点在左下角
原点在左上角
对于图像必须为
交叉数据存储标志
两路奇偶交叉
图像信息字段
包含一个自由格式的,长度是图像由“图像信息字段”指定。它常常被忽略(即偏移处值为),注意其最大可以含有个字符。如果需要存储更多信息,可以放在图像数据之后。
颜色表数据
如果颜色表类型为,则该域不存在,否则越过该域直接读取图像颜色表规格中描述了每项的字节数,为,,之一。
颜色数据,存放顺序为:
图片类型:压缩格式
图像信息字段长度
本字段是字节无符号整型,指出图像信息字段(见本子表的后面)长度,其取值范围是到,当它为时表示没有图像的信息字段。
颜色表类型
表示没有颜色表,表示颜色表存在。由于本格式是无颜色表的,因此此项通常被忽略。
图像类型码
该字段总为,这也是此类型为格式的原因。
颜色表规格字段
颜色表首址
颜色表首的入口索引,整型(低位-高位)
如果颜色表字段为,则忽略该字段
颜色表的长度
颜色表的表项总数,整型(低位高位)
颜色表项位数
位数(),代表位,代表位,代表

我要回帖

更多关于 tga格式转换器 的文章

 

随机推荐