tga 文件头信息如下图:
代码如下:
#include "XEPrerequisites.h"
namespace XE
{
struct TGA_HEADER
{
unsigned short _width; ///<tga宽度
unsigned short _height; ///<tga高度
unsigned char _bitsPerPixel; ///<tga像素位数
unsigned char _describe; ///<tga描述字节
};
class _XEExport TGA
{
public:
TGA();
~TGA();
bool load(const std::string& fileName);
bool load(unsigned char* data);
bool getPixel(unsigned int index, unsigned char& red, unsigned char& green, unsigned char& blue, unsigned char& alpha) const;
bool setPixel(unsigned int index, unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha);
bool save(const std::string& fileName);
bool saveRect(const std::string& fileName, const Rect& rect);
///设置头信息
void setHeader(const TGA_HEADER& header) { m_header = header; }
///获得头信息
const TGA_HEADER& getHeader() { return m_header; }
///设置数据块
void setData(unsigned char * data) { if( m_data )free(m_data); m_data = data; }
///获得数据块
unsigned char * getData() { return m_data; }
///设置数据块大小
void setDataSize(unsigned int dataSize) { m_dataSize = dataSize; }
///获得数据块大小
unsigned int getDataSize() { return m_dataSize; }
///设置像素字节大小
void setBytesPerPixel(unsigned int bytesPerPixe) { m_bytesPerPixel = bytesPerPixe; }
///获得像素字节大小
unsigned int getBytesPerPixel() { return m_bytesPerPixel; }
private:
bool _loadUncompressedTGA(FILE *);
bool _loadCompressedTGA(FILE *);
bool _loadUncompressedTGA(unsigned char* data);
bool _loadCompressedTGA(unsigned char* data);
private:
TGA_HEADER m_header; ///< 头信息
unsigned char * m_data; ///< 数据块
unsigned int m_dataSize; ///< 数据块大小
unsigned int m_bytesPerPixel; ///< 像素字节大小
};
}//XE
#endif __XETGA_H__
namespace XE
{
TGA::TGA()
{
m_data = 0;
}
TGA::~TGA()
{
if( m_data )
{
free(m_data);
m_data = 0;
}
}
bool TGA::load(const std::string& fileName)
{
FILE * __file = fopen(fileName.c_str(),"rb");
if(__file == NULL)
{
return false;
}
unsigned char __header[12];
if(fread(&__header, sizeof(__header), 1, __file) == 0)
{
fclose(__file);
return false;
}
//未压缩TGA文件头
unsigned char uTGAcompare[12] = {0,0,2, 0,0,0,0,0,0,0,0,0};
//压缩TGA文件头
unsigned char cTGAcompare[12] = {0,0,10,0,0,0,0,0,0,0,0,0};
if(memcmp(uTGAcompare, &__header, sizeof(__header)) == 0)
{
return _loadUncompressedTGA(__file);
}
else if(memcmp(cTGAcompare, &__header, sizeof(__header)) == 0)
{
return _loadCompressedTGA(__file);
}
else
{
fclose(__file);
return false;
}
}
bool TGA::load(unsigned char* data)
{
unsigned char __header[12];
memcpy(__header, data, 12);
//未压缩TGA文件头
unsigned char uTGAcompare[12] = {0,0,2, 0,0,0,0,0,0,0,0,0};
//压缩TGA文件头
unsigned char cTGAcompare[12] = {0,0,10,0,0,0,0,0,0,0,0,0};
if(memcmp(uTGAcompare, &__header, sizeof(__header)) == 0)
{
return _loadUncompressedTGA(data);
}
else if(memcmp(cTGAcompare, &__header, sizeof(__header)) == 0)
{
return _loadCompressedTGA(data);
}
return false;
}
bool TGA::_loadUncompressedTGA(unsigned char* data)
{
//unsigned char _header[6];
//memcpy(_header, data + 12, 6);
//
//m_width = _header[1] * 256 + _header[0]; // Determine The TGA Width (highbyte*256+lowbyte)
//m_height = _header[3] * 256 + _header[2]; // Determine The TGA Height (highbyte*256+lowbyte)
//m_bitsPerPixel = _header[4]; // Determine the bits per pixel
memcpy(&m_header, data + 12, sizeof(m_header));
if((m_header._bitsPerPixel != 24) && (m_header._bitsPerPixel !=32))
{
return false;
}
m_bytesPerPixel = (m_header._bitsPerPixel / 8); // Compute the number of BYTES per pixel
m_dataSize = (m_bytesPerPixel * m_header._width * m_header._height); // Compute the total amout ofmemory needed to store data
m_data = (unsigned char*)malloc(m_dataSize); // Allocate that much memory
if(m_data == NULL)
{
return false;
}
memcpy(m_data, data + 18, m_dataSize);
//// Byte Swapping Optimized By Steve Thomas
//for(unsigned int cswap = 0; cswap < m_dataSize; cswap += m_bytesPerPixel)
//{
// m_data[cswap] ^= m_data[cswap+2] ^=
// m_data[cswap] ^= m_data[cswap+2];
//}
return true;
}
bool TGA::_loadUncompressedTGA(FILE * file)
{
//unsigned char _header[6];
//if(fread(_header, sizeof(_header), 1, file) == 0)
//{
// fclose(file);
// return false;
//}
//m_width = _header[1] * 256 + _header[0]; // Determine The TGA Width (highbyte*256+lowbyte)
//m_height = _header[3] * 256 + _header[2]; // Determine The TGA Height (highbyte*256+lowbyte)
//m_bitsPerPixel = _header[4]; // Determine the bits per pixel
if(fread(&m_header, sizeof(m_header), 1, file) == 0)
{
fclose(file);
return false;
}
if((m_header._bitsPerPixel != 24) && (m_header._bitsPerPixel !=32))
{
fclose(file);
return false;
}
m_bytesPerPixel = (m_header._bitsPerPixel / 8); // Compute the number of BYTES per pixel
m_dataSize = (m_bytesPerPixel * m_header._width * m_header._height); // Compute the total amout ofmemory needed to store data
m_data = (unsigned char*)malloc(m_dataSize); // Allocate that much memory
if(m_data == NULL)
{
fclose(file);
return false;
}
if(fread(m_data, 1, m_dataSize, file) != m_dataSize) // Attempt to read image data
{
free(m_data);
fclose(file);
return false;
}
// Byte Swapping Optimized By Steve Thomas
/*for(unsigned int cswap = 0; cswap < m_dataSize; cswap += m_bytesPerPixel)
{
m_data[cswap] ^= m_data[cswap+2] ^=
m_data[cswap] ^= m_data[cswap+2];
}*/
fclose(file);
return true;
}
bool TGA::save(const std::string& fileName)
{
FILE* __file = fopen(fileName.c_str(),"wb+");
if(__file == NULL)
{
return false;
}
if(m_data == NULL)
{
return false;
}
unsigned char uTGAcompare[12] = {0,0,2, 0,0,0,0,0,0,0,0,0};
fseek(__file,0,SEEK_SET);
fwrite(uTGAcompare, sizeof(uTGAcompare), 1, __file);
fwrite(&m_header._width, sizeof(m_header._width), 1, __file);
fwrite(&m_header._height, sizeof(m_header._height), 1, __file);
fwrite(&m_header._bitsPerPixel, sizeof(m_header._bitsPerPixel), 1, __file);
fwrite(&m_header._describe, sizeof(m_header._describe), 1, __file);
unsigned char* __buffer = (unsigned char*) malloc(m_dataSize);
unsigned char* __buffer_temp = __buffer;
size_t __write_buffer_size = 0;
if (__buffer == NULL)
{
fclose(__file);
return false;
}
for ( int __row = 0; __row < m_header._height; __row++ )
{
unsigned char* __pixel_buffer = m_data + __row * m_header._width * 4;
for ( int __column = 0; __column < m_header._width; __column++ )
{
switch ( m_header._bitsPerPixel )
{
case 24:
{
unsigned char __red = *__pixel_buffer++;
unsigned char __green = *__pixel_buffer++;
unsigned char __blue = *__pixel_buffer++;
unsigned char __alpha = *__pixel_buffer++;
*__buffer_temp++ = __blue;
*__buffer_temp++ = __green;
*__buffer_temp++ = __red;
__alpha;
__write_buffer_size+=3;
}
break;
case 32:
{
unsigned char __red = *__pixel_buffer++;
unsigned char __green = *__pixel_buffer++;
unsigned char __blue = *__pixel_buffer++;
unsigned char __alpha = *__pixel_buffer++;
*__buffer_temp++ = __blue;
*__buffer_temp++ = __green;
*__buffer_temp++ = __red;
*__buffer_temp++ = __alpha;
__write_buffer_size+=4;
}
break;
default:
return false;
}
}
}
size_t __write_file_size = fwrite( __buffer, 1, __write_buffer_size, __file);
assert( __write_file_size == __write_buffer_size );
if( __write_file_size != __write_buffer_size )
{
free(__buffer);
fclose(__file);
return false;
}
free(__buffer);
fclose(__file);
return true;
}
bool TGA::saveRect(const std::string& fileName, const Rect& rect)
{
FILE* __file = fopen(fileName.c_str(),"wb+");
if(__file == NULL)
{
return false;
}
if(m_data == NULL)
{
return false;
}
unsigned char uTGAcompare[12] = {0,0,2, 0,0,0,0,0,0,0,0,0};
Rect _rect(rect);
if( _rect.top < 0.0f )
_rect.top = 0.0f;
if( _rect.left < 0.0f )
_rect.left = 0.0f;
if( _rect.bottom > m_header._height )
_rect.bottom = m_header._height;
if( _rect.right > m_header._width )
_rect.right = m_header._width;
unsigned short _width = _rect.right - _rect.left;
unsigned short _height = _rect.bottom - _rect.top;
fseek(__file,0,SEEK_SET);
fwrite(uTGAcompare, sizeof(uTGAcompare), 1, __file);
fwrite(&_width, sizeof(_width), 1, __file);
fwrite(&_height, sizeof(_height), 1, __file);
fwrite(&m_header._bitsPerPixel, sizeof(m_header._bitsPerPixel), 1, __file);
fwrite(&m_header._describe, sizeof(m_header._describe), 1, __file);
unsigned int _dataSize = _width * _height * m_bytesPerPixel;
unsigned char* __buffer = (unsigned char*) malloc(_dataSize);
unsigned char* __buffer_temp = __buffer;
size_t __write_buffer_size = 0;
if (__buffer == NULL)
{
fclose(__file);
return false;
}
for ( int __row = _rect.top; __row < _rect.bottom; __row++ )
{
unsigned char* __pixel_buffer = m_data + __row * m_header._width * 4 + (int)_rect.left * 4;
for ( int __column = _rect.left; __column < _rect.right; __column++ )
{
switch ( m_header._bitsPerPixel )
{
case 24:
{
unsigned char __red = *__pixel_buffer++;
unsigned char __green = *__pixel_buffer++;
unsigned char __blue = *__pixel_buffer++;
unsigned char __alpha = *__pixel_buffer++;
*__buffer_temp++ = __blue;
*__buffer_temp++ = __green;
*__buffer_temp++ = __red;
__alpha;
__write_buffer_size+=3;
}
break;
case 32:
{
unsigned char __red = *__pixel_buffer++;
unsigned char __green = *__pixel_buffer++;
unsigned char __blue = *__pixel_buffer++;
unsigned char __alpha = *__pixel_buffer++;
*__buffer_temp++ = __blue;
*__buffer_temp++ = __green;
*__buffer_temp++ = __red;
*__buffer_temp++ = __alpha;
__write_buffer_size+=4;
}
break;
default:
return false;
}
}
}
size_t __write_file_size = fwrite( __buffer, 1, __write_buffer_size, __file);
assert( __write_file_size == __write_buffer_size );
if( __write_file_size != __write_buffer_size )
{
free(__buffer);
fclose(__file);
return false;
}
free(__buffer);
fclose(__file);
return true;
}
bool TGA::_loadCompressedTGA(unsigned char* data)
{
return false;
}
bool TGA::getPixel(unsigned int index, unsigned char& red, unsigned char& green, unsigned char& blue, unsigned char& alpha) const
{
if( index < 0 || index > m_dataSize )
return false;
unsigned char* __data = m_data + index * m_bytesPerPixel;
switch ( m_header._bitsPerPixel )
{
case 24:
{
red = *__data++;
green = *__data++;
blue = *__data++;
alpha;
}
break;
case 32:
{
red = *__data++;
green = *__data++;
blue = *__data++;
alpha = *__data++;;
}
break;
default:
return false;
}
return true;
}
bool TGA::setPixel(unsigned int index, unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha)
{
if( index < 0 || index > m_dataSize )
return false;
unsigned char* __data = m_data + index * m_bytesPerPixel;
switch ( m_header._bitsPerPixel )
{
case 24:
{
*__data++ = red;
*__data++ = green;
*__data++ = blue;
alpha;
}
break;
case 32:
{
*__data++ = red;
*__data++ = green;
*__data++ = blue;
*__data++ = alpha;
}
break;
default:
return false;
}
return true;
}
bool TGA::_loadCompressedTGA(FILE * file)
{
//unsigned char _header[6];
//if(fread(_header, sizeof(_header), 1, file) == 0)
//{
// fclose(file);
// return false;
//}
//m_width = _header[1] * 256 + _header[0]; // Determine The TGA Width (highbyte*256+lowbyte)
//m_height = _header[3] * 256 + _header[2]; // Determine The TGA Height (highbyte*256+lowbyte)
//m_bitsPerPixel = _header[4]; // Determine the bits per pixel
if(fread(&m_header, sizeof(m_header), 1, file) == 0)
{
fclose(file);
return false;
}
if((m_header._bitsPerPixel != 24) && (m_header._bitsPerPixel !=32))
{
fclose(file);
return false;
}
m_bytesPerPixel = (m_header._bitsPerPixel / 8); // Compute BYTES per pixel
m_dataSize = (m_bytesPerPixel * m_header._width * m_header._height); // Compute amout of memory needed to store image
m_data = (unsigned char *)malloc(m_dataSize); // Allocate that much memory
if(m_data == NULL)
{
fclose(file);
return false;
}
unsigned int pixelcount = m_header._width * m_header._height; // Nuber of pixels in the image
unsigned int currentpixel = 0; // Current pixel being read
unsigned int currentbyte = 0; // Current byte
unsigned char * colorbuffer = (unsigned char *)malloc(m_bytesPerPixel); // Storage for 1 pixel
do
{
unsigned char chunkheader = 0;
if(fread(&chunkheader, sizeof(unsigned char), 1, file) == 0) // Read in the 1 byte header
{
fclose(file);
free(m_data);
return false; // Return failed
}
if(chunkheader < 128) // If the ehader is < 128, it means the that is the number of RAW color packets minus 1
{ // that follow the header
chunkheader++; // add 1 to get number of following color values
for(short counter = 0; counter < chunkheader; counter++) // Read RAW color values
{
if(fread(colorbuffer, 1, m_bytesPerPixel, file) != m_bytesPerPixel) // Try to read 1 pixel
{
fclose(file);
free(colorbuffer);
free(m_data);
return false; // Return failed
}
// write to memory
m_data[currentbyte ] = colorbuffer[2]; // Flip R and B vcolor values around in the process
m_data[currentbyte + 1 ] = colorbuffer[1];
m_data[currentbyte + 2 ] = colorbuffer[0];
if(m_bytesPerPixel == 4) // if its a 32 bpp image
{
m_data[currentbyte + 3] = colorbuffer[3]; // copy the 4th byte
}
currentbyte += m_bytesPerPixel; // Increase thecurrent byte by the number of bytes per pixel
currentpixel++; // Increase current pixel by 1
if(currentpixel > pixelcount) // Make sure we havent read too many pixels
{
fclose(file);
free(colorbuffer);
free(m_data);
return false; // Return failed
}
}
}
else // chunkheader > 128 RLE data, next color reapeated chunkheader - 127 times
{
chunkheader -= 127; // Subteact 127 to get rid of the ID bit
if(fread(colorbuffer, 1, m_bytesPerPixel, file) != m_bytesPerPixel) // Attempt to read following color values
{
fclose(file);
free(colorbuffer);
free(m_data);
return false;
}
for(short counter = 0; counter < chunkheader; counter++) // copy the color into the image data as many times as dictated
{ // by the header
m_data[currentbyte ] = colorbuffer[2]; // switch R and B bytes areound while copying
m_data[currentbyte + 1 ] = colorbuffer[1];
m_data[currentbyte + 2 ] = colorbuffer[0];
if(m_bytesPerPixel == 4) // If TGA images is 32 bpp
{
m_data[currentbyte + 3] = colorbuffer[3]; // Copy 4th byte
}
currentbyte += m_bytesPerPixel; // Increase current byte by the number of bytes per pixel
currentpixel++; // Increase pixel count by 1
if(currentpixel > pixelcount) // Make sure we havent written too many pixels
{
fclose(file);
free(colorbuffer);
free(m_data);
return false; // Return failed
}
}
}
}
while(currentpixel < pixelcount); // Loop while there are still pixels left
fclose(file); // Close the file
return true; // return success
}
} //XE