tga 文件头信息如下图: 代码如下: #ifndef __XETGA_H__ #define __XETGA_H__ #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__ #include "XEStableHeaders.h" #include "XETga.h" #include "XERect.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