#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(); }