tga-load

#ifndef _tga_h_
#define _tga_h_

/*
Image ID length (field 1)
		0 - 255 The number of bytes that the image ID field consists of. 
		The image ID field can contain any information, 
		but it is common for it to contain the date and time the image was created or a serial number. 
		As of version 2.0 of the TGA spec, the date and time the image was created is catered for in the extension area.

Color map type (field 2)

		has the value:
		0 if image file contains no color map
		1 if present
		2-127 reserved by Truevision
		128-255 available for developer use

Image type (field 3)

		is enumerated in the lower three bits, with the fourth bit as a flag for RLE. Some possible values are:
			0	no image data is present
			1	uncompressed color-mapped image
			2	uncompressed true-color image
			3	uncompressed black-and-white (grayscale) image
			9	run-length encoded color-mapped image
			10	run-length encoded true-color image
			11	run-length encoded black-and-white (grayscale) image

	Image type 1 and 9: Depending on the Pixel Depth value, 
	image data representation is an 8, 15, or 16 bit index into a color map that defines the color of the pixel. 
	Image type 2 and 10: The image data is a direct representation of the pixel color. 
	For a Pixel Depth of 15 and 16 bit, each pixel is stored with 5 bits per color. 
	If the pixel depth is 16 bits, the topmost bit is reserved for transparency. 
	For a pixel depth of 24 bits, each pixel is stored with 8 bits per color. 
	A 32 bit pixel depth defines an additional 8 bit alpha channel. 
	Image type 3 and 11: The image data is a direct representation of grayscale data. 
	The pixel depth is 8 bits for images of this type.

Color map specification (field 4)

	has three subfields:

	First entry index (2 bytes): offset into the color map table
	Color map length (2 bytes): number of entries
	Color map entry size (1 byte): number of bits per pixel


Image specification (field 5)

	has six subfields:

	1.X-origin (2 bytes): absolute coordinate of lower-left corner for displays where origin is at the lower left
	2.Y-origin (2 bytes): as for X-origin
	3.Image width (2 bytes): width in pixels
	4.Image height (2 bytes): height in pixels
	5.Pixel depth (1 byte): bits per pixel
	6.Image descriptor (1 byte): bits 3-0 give the alpha channel depth, bits 5-4 give direction


Image and color map data
	Field no. 			Length 							Field 								Description
	6 			From image ID length field 				Image ID 			Optional field containing identifying information
	7 			From color map specification field 		Color map data 		Look-up table containing color map data
	8 			From image specification field 			Image data 			Stored according to the image descriptor

*/



typedef struct _TGAHEADER{
	char  idlength;					// Length of the image ID field-after header
	char  colourmaptype;			// Whether a color map is included
	char  datatypecode;				// type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed
	short int colourmaporigin;		// first colour map entry in palette
	short int colourmaplength;		// number of colours in palette
	char  colourmapdepth;			// number of bits per palette entry 15,16,24,32
	short int x_origin;				// image x origin
	short int y_origin;				// image y origin
	short width;					// image width in pixels
	short height;					// image height in pixels
	char  bitsperpixel;				// image bits per pixel 8,16,24,32
	char  imagedescriptor;			// image descriptor bits (vh flip bits)


} TGAHeader;


struct Pixel32
{
	unsigned char r,g,b,a;
};

#include <string>
using std::string;
class Tga32
{
public:
	Tga32();
	~Tga32();
	bool load(std::string file);
	void unload();
	void save(std::string file);
protected:
	void merge(Pixel32*pixel,unsigned char*p,int bytesRead,unsigned char datatypecode = 2);
	void mergeGrayScale(Pixel32*pixel,unsigned char*p);
private:
	short	mW;
	short	mH;
	void*	mData;	
};

#endif
#include "tga.h"
#include <fstream>
#include <iostream>
#include <assert.h>
using std::ofstream;
using std::ifstream;

Tga32::Tga32()
{	
	mData = 0;	
}

Tga32::~Tga32()
{
	if(mData) 
	{
		free(mData);
		mData = 0;
	}
}

bool Tga32::load(std::string file)
{
	ifstream in(file.c_str(),std::ios::binary);
	if(!in.is_open())
	{
		mData = NULL;
		return false;
	}

	TGAHeader tgaHeader;
	in.read((char*)&tgaHeader.idlength,1);
	in.read((char*)&tgaHeader.colourmaptype,1);
	in.read((char*)&tgaHeader.datatypecode,1);
	in.read((char*)&tgaHeader.colourmaporigin,2);
	in.read((char*)&tgaHeader.colourmaplength,2);
	in.read((char*)&tgaHeader.colourmapdepth,1);
	in.read((char*)&tgaHeader.x_origin,2);
	in.read((char*)&tgaHeader.y_origin,2);
	in.read((char*)&tgaHeader.width,2);
	in.read((char*)&tgaHeader.height,2);
	in.read((char*)&tgaHeader.bitsperpixel,1);
	in.read((char*)&tgaHeader.imagedescriptor,1);

	mW = tgaHeader.width;
	mH = tgaHeader.height;

	int sizePixel = sizeof(Pixel32);
	mData = malloc(mH*mW*sizeof(Pixel32));
	Pixel32* pixelPtr = (Pixel32*)mData;

	memset(mData,0,mH*mW*sizeof(Pixel32));
	int skipOver = tgaHeader.idlength + tgaHeader.colourmaptype*tgaHeader.colourmaplength;

	// skip non-useful data
	in.seekg(skipOver,std::ios_base::cur);	
	int bytesRead = tgaHeader.bitsperpixel / 8;
	unsigned char p[5];
	int n = 0;
	while(n < mW*mH)
	{
		if(tgaHeader.datatypecode == 2)
		{
			in.read((char*)p,bytesRead);
			merge(&pixelPtr[n],p,bytesRead);
			n++;
		}
		else if(tgaHeader.datatypecode == 3)
		{
			in.read((char*)p,1);
			mergeGrayScale(&pixelPtr[n],p);
			n++;
		}
		else if(tgaHeader.datatypecode == 10)
		{
			//rle
			in.read((char*)p,bytesRead+1);	// + rle-counter's number
			merge(&pixelPtr[n],&p[1],bytesRead);
			n++;

			int count = p[0] & 0x7f;
			if(p[0] & 0x80)		//  RLE chunk
			{
				for(int i = 0; i < count;i++)
				{
					merge(&pixelPtr[n],&p[1],bytesRead);
					n++;
				}
			}
			else
			{
				for(int i = 0; i < count;i ++)
				{
					in.read((char*)p,bytesRead);
					merge(&pixelPtr[n],p,bytesRead);
					n++;
				}
			}
		}
		else if(tgaHeader.datatypecode == 11)
		{
			in.read((char*)p,1+1);	// + rle-counter's number
			mergeGrayScale(&pixelPtr[n],&p[1]);
			n++;

			int count = p[0] & 0x7f;

			if(p[0] & 0x80)		// 是否采用计数  RLE chunk
			{
				for(int i = 0; i < count;i++)
				{
					mergeGrayScale(&pixelPtr[n],&p[1]);
					n++;
				}
			}
			else
			{
				for(int i = 0; i < count;i ++)
				{
					in.read((char*)p,1);
					mergeGrayScale(&pixelPtr[n],p);
					n++;
				}
			}
		}
	}	
}

void Tga32::merge(Pixel32*pixel,unsigned char*p,int bytesRead,unsigned char datatypecode)
{
	if(bytesRead == 4)
	{
		pixel->r = p[2];
		pixel->g = p[1];
		pixel->b = p[0];
		pixel->a = p[3];
	}
	else if(bytesRead == 3)
	{
		pixel->r = p[2];
		pixel->g = p[1];
		pixel->b = p[0];
		pixel->a = 255;
	}
	else if (bytesRead == 2) 
	{
		pixel->r = (p[1] & 0x7c) << 1;
		pixel->g = ((p[1] & 0x03) << 6) | ((p[0] & 0xe0) >> 2);
		pixel->b = (p[0] & 0x1f) << 3;
		pixel->a = (p[1] & 0x80);
	}
}

void Tga32::mergeGrayScale(Pixel32*pixel,unsigned char*p)
{
	pixel->r = pixel->g = pixel->b = p[0];
	pixel->a = 255;
}

void Tga32::save(std::string file)
{
	assert(mData != 0);
	ofstream out(file.c_str(),std::ios::binary);
	if(!out.is_open()) return;

	out.put(0);
	out.put(0);
	out.put(2);                         /* uncompressed RGB */
	out.put(0); out.put(0);
	out.put(0); out.put(0);
	out.put(0);
	out.put(0); out.put(0);           /* X origin */
	out.put(0); out.put(0);           /* y origin */
	out.put(mW & 0xFF);
	out.put((mW >> 8) & 0xFF);
	out.put(mH & 0xFF);
	out.put((mH >> 8) & 0xFF);
	out.put(32);
	out.put(0x80);

	Pixel32 *pPixel = (Pixel32*)mData;
	for(int i = 0; i < mW * mH;i++)
	{
		out.put(pPixel[i].b);
		out.put(pPixel[i].g);
		out.put(pPixel[i].r);
		out.put(pPixel[i].a);
	}
	out.close();
}

你可能感兴趣的:(tga-load)