<style type="text/css">
<!--
@page
{margin:2cm}
pre.cjk
{font-family:"DejaVu Sans Condensed",monospace}
p
{margin-bottom:0.21cm}
-->
</style>
自己编写一个读取TGA文件的类
TGA文件,也就是Targa文件,是一种图片的格式,在游戏和绘图领域中用得比较广泛。TGA文件是位图文件,存储着各个像素的颜色信息。本来想直接使用《OpenGL超级宝典》里面现成的TGA文件载入函数,然后修改成一个类,但遗憾的是,书上的代码并不适合于所有的TGA文件。有些由GIMP和Photoshop创建TGA文件无法载入。这真是让我感到不爽。好在自己有了几年的C/C++编程经验,通过上网查询TGA文件的格式规范,我终于了解到了TGA文件的奥秘。带着一份自信和一点探索精神,我用了大概一天的时间完成了TGA文件的读取。
首先我们看看GIMP中有关TGA文件格式的处理。
从上图我们可以知道,TGA分为RLE压缩和非RLE压缩,而且TGA文件的起始位置可以选择左下或者左上。RLE全称游程长度编码(RunLengthEncoded),它通过一种简单的算法来对颜色进行压缩。比如说『1,1,1,1,1,1』就可以表示为『6,1』,其中6表示循环的次数,1表示循环的值。这是一种非常简单的压缩算法。在我的资源中详细地讲述了如何解压缩RLE。如果你在Windows下安装了Photoshop,你会发现TGA文件可以保存为16bit、24bit和32bit三种类型。这些就是我们可以TGA文件的全部了。
可是TGA文件又远远不止这些,有些TGA文件具有索引的功能,也就是说图像数据保存的并不是颜色,而是索引。可以根据索引来确定每一个像素的颜色。一篇介绍TGA格式文件的说明中写道,TGA文件保存索引可以有效地节约空间,而这些颜色保存在一个颜色映射域(colormapfield)中。所以这无疑是给我们增添了读取的难度。说明只讨论了4种常用的TGA格式文件的读取方法。我就是以这个说明为基础来编写TGA格式文件的。下面是这个页面的截图:
我的源代码可以在这里找到,我用了《OpenGL超级宝典》的Pyramid例子来测试TGA文件的读取。我的开发环境是Ubuntu+QtCreator2.41。下面是例子的截图:
程序可以通过[w][s][a][d]键上下左右移动金字塔。当然这不是主要的,可以看到,这个图形可以顺利地载入TGA格式的文件。在我的资源中,我随意地创建了一个16bit、16bitRLE、24bit、24bitRLE、32bit、32bitRLE的TGA图像,当你修改文件GLWidget.cpp文件第27行的文件名,可以试试其它格式的文件载入看看。
出于版面考虑,我只列出部分载入TGA文件的代码,供大家参考。完整代码在我的资源中。
#ifndef TGAFILE_H
#define TGAFILE_H
#pragma pack( push, 1 )
class TGAFile
{
public:
TGAFile( void );
bool Load( const char* fileName );
static const char* GetLastError( void );
inline signed short Width( void ) { return m_Width; }
inline signed short Height( void ) { return m_Height; }
inline unsigned short GLInternatFormat( void ) { return 0x1908; }// GL_RGBA8
inline unsigned short GLFormat( void ) { return 0x80E1; }// GL_BGRA
inline unsigned char* Data( void ) { return m_pImageData; }
private:
bool ReadIDField( void* );
bool ReadColorMapData( void* );
void DecodeColorMap( void );
bool DecodeImageData( void* );
bool DecodeRLEDataWithColorMap( void* );
bool DecodeRLE( void* );
bool ReadImageData( void* );
unsigned char GetIndexSize( unsigned long );
void GetRGBA( unsigned char*, unsigned char&, unsigned char&,
unsigned char&, unsigned char& );
unsigned char m_IDFieldLength;
unsigned char m_ColorMapType;
unsigned char m_ImageType;
// 颜色映射(Color map specfication)
unsigned short m_ColorMapOrigin;
unsigned short m_ColorMapLength;
unsigned char m_ColorMapEntrySize;
// 图像Image Specification
signed short m_OriginX;
signed short m_OriginY;
signed short m_Width;
signed short m_Height;
unsigned char m_PixelSize;
unsigned char m_ImageDescriptor;
// 注意,此文件解码后像素大小始终是32位的
unsigned char* m_pIDField; // 图像身份域,长度为m_nIDField
unsigned char* m_pColorMapData;// 颜色映射域,长度为m_ColorMapLength
unsigned char* m_pImageData; // 图像数据,长度为m_Width * m_Height * m_PixelSize;
static const char* s_pErrorMessage;
};
#pragma pack( pop )
#endif // TGAFILE_H
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include "TGAFile.h"
// 错误标志
#define _FILE_NOT_EXIST_ "Cannot open file, because the file does not exist."
#define _HEADER_BROKEN_ "The TGA file header is broken or unreadable, please check if it is a correct TGA file."
#define _ID_FIELD_BROKEN_ "The TGA identity field is broken in some minor cases, please use another file."
#define _COLOR_MAP_BROKEN_ "The TGA color map data is broken in some minor cases, please use another file."
#define _NO_SUCH_PIXEL_SIZE_ \
"There is no such pixel size for TGA file reader to handle, "\
"The TGA file reader support only 16, 24, and 32 bit pixel size."\
"it happens when the header is corrupted."
#define _IMAGE_DATA_BROKEN_ "The image data is broken, please check its integrity or use another file."
#define _PACKAGE_HEADER_BROKEN_ \
"The image package is broken, please check whether the image is correct."
#define _PACKAGE_DATA_BROKEN_ \
"The image package data is broken, please check whether the image is correct."
//-----------------------------------------------------------------------------
// 静态成员
const char* TGAFile::s_pErrorMessage = 0;
const char* TGAFile::GetLastError( void )
{
return s_pErrorMessage;
}
//-----------------------------------------------------------------------------
TGAFile::TGAFile( void )
{
memset( &m_IDFieldLength, 0, sizeof( TGAFile ) );// 清零
}
//-----------------------------------------------------------------------------
bool TGAFile::Load( const char* fileName )
{
FILE* pFile = fopen( fileName, "rb" );// 打开文件
if ( pFile == 0 )
{
s_pErrorMessage = _FILE_NOT_EXIST_;
return false;
}
// 将TGA文件头复制过来
if ( fread( &m_IDFieldLength, 18, 1, pFile ) < 1 )
{
s_pErrorMessage = _HEADER_BROKEN_;
return false;
}
if ( m_IDFieldLength > 0 )
{ if ( !ReadIDField( pFile ) ) return false; }// 读取图像的ID域
if ( m_ColorMapLength > 0 )
{ if ( !ReadColorMapData( pFile ) ) return false; }// 读取颜色映射域
// 读取文件数据
switch ( m_ImageType )
{
case 1:// 有颜色映射的图像
DecodeColorMap( );
if ( !DecodeImageData( pFile ) ) return false;
break;
case 2:// 无颜色映射,RGB图像
if ( !ReadImageData( pFile ) ) return false;
break;
case 9:// 游程长度编码的解码(RLE),带颜色映射
DecodeColorMap( );
if ( !DecodeRLEDataWithColorMap( pFile ) ) return false;
case 10:// 游程长度编码的解码(RLE)
if ( !DecodeRLE( pFile ) ) return false;
}
fclose( pFile );// 关闭文件
return true;
}
……
分享到:
相关推荐
本来想直接使用《OpenGL超级宝典》里面现成的TGA文件载入函数,然后修改成一个类,但遗憾的是,书上的代码并不适合于所有的TGA文件。有些由GIMP和Photoshop创建TGA文件无法载入。这真是让我感到不爽。好在自己有了几...
用于读写文件的类,比较方便!
请编写一个文件操作的封装类,其要求如下: 需要提供open/read/write/lseek/close等函数的封装函数 该类要提供数据缓存服务。 调用该类的写操作接口时,数据要首先写到缓存,然后再根据策略写到文件中。 调用该类的...
TGA文件读取,代码,详细,函数体,直接使用。
请编写一个文件操作的封装类,其要求如下: 需要提供open/read/write/lseek/close等函数的封装函数 该类要提供数据缓存服务。 调用该类的写操作接口时,数据要首先写到缓存,然后再根据策略写到文件中。 调用该类的...
这是一个简单的C#编写的读取文件和写入文件的类。
这是我用c++编写的程序,首先分别从两个文件中读取文件中的数据,然后再将这两个文件中的数据相加,并把和写到另外一个文件中,适合正在纠结与文件读写的学者
使用JAVA编写一个使用TCP协议传输文件的Socket,实现客户端向服务器端发送一个文件,服务器端接收之后按相同的文件名在指定的目录下保存文件
基于MIT许可的读取TGA DDS图片文件的程序包,,可以用于三维软件的纹理贴图文件的读取
编写程序,该程序实现打开一个文本文件,每次读取一行内容,将每行作为一个字符串读入,并将字符串输出显示到屏幕上。
自己编写的一个csv文件读写类,可以实现读入csv文件并封装为一个对象,还可以动态生成csv对象并保存为csv文件
C#编写的读写ini文件类和发送邮件类(vs.net2003C#), 有好多的程序习惯把配置写到ini文件中,此代码包括 ini操作类和邮件发送类.只要把cs放到到自己的项目中就可以读写ini和发送邮件了.在Main函数中列举了类的使用....
C#读取tga图片格式的源代码,具体见代码,里面有一个结构体和实现方法。
参看文本文件"学生成绩.txt", 编写一个类, 读取文件, 找出语文成绩最高的人的姓名, 按数学成绩由高到低排列, 删除"学生成绩.txt"文件中至尊宝的所有成绩,添加别外一个人的成绩: 008 项少龙 语文: 57 数学: 96 思想...
java通过snakeyaml类能非常方便的操作,读写yaml文件。
读取一个文件中的整数,并将它们从小到大排序,最后输出排序后到另一个文件中
遥感 利用vs编写各类文件的读取和保存的程序 简单方便操作
在WinAPI基础上编写的ini文件的读写类。
java编写,读取文件,把文件中的空格去掉并换行,生成一个新文件
c# 文件读写类,可以用于读取更改定点的文件