3 * Purpose: Platform Independent TGA Image Class Loader and Writer
\r
4 * 05/Jan/2001 Davide Pizzolato - www.xdp.it
\r
5 * CxImage version 6.0.0 02/Feb/2008
\r
10 #if CXIMAGE_SUPPORT_TGA
\r
12 #include "ximaiter.h"
\r
14 // Definitions for image types.
\r
19 #define TGA_RLEMap 9
\r
20 #define TGA_RLERGB 10
\r
21 #define TGA_RLEMono 11
\r
22 #define TGA_CompMap 32
\r
23 #define TGA_CompMap4 33
\r
25 ////////////////////////////////////////////////////////////////////////////////
\r
26 #if CXIMAGE_SUPPORT_DECODE
\r
27 ////////////////////////////////////////////////////////////////////////////////
\r
28 bool CxImageTGA::Decode(CxFile *hFile)
\r
30 if (hFile == NULL) return false;
\r
36 if (hFile->Read(&tgaHead,sizeof(tgaHead),1)==0)
\r
37 cx_throw("Not a TGA");
\r
42 switch (tgaHead.ImageType){
\r
46 bCompressed = false;
\r
54 cx_throw("Unknown TGA image type");
\r
57 if (tgaHead.ImageWidth==0 || tgaHead.ImageHeight==0 || tgaHead.PixelDepth==0 || tgaHead.CmapLength>256)
\r
58 cx_throw("bad TGA header");
\r
60 if (tgaHead.PixelDepth!=8 && tgaHead.PixelDepth!=15 && tgaHead.PixelDepth!=16 && tgaHead.PixelDepth!=24 && tgaHead.PixelDepth!=32)
\r
61 cx_throw("bad TGA header");
\r
63 if (info.nEscape == -1){
\r
64 head.biWidth = tgaHead.ImageWidth ;
\r
65 head.biHeight= tgaHead.ImageHeight;
\r
66 info.dwType = CXIMAGE_FORMAT_TGA;
\r
70 if (tgaHead.IdLength>0) hFile->Seek(tgaHead.IdLength,SEEK_CUR); //skip descriptor
\r
72 Create(tgaHead.ImageWidth, tgaHead.ImageHeight, tgaHead.PixelDepth, CXIMAGE_FORMAT_TGA);
\r
73 #if CXIMAGE_SUPPORT_ALPHA // <vho>
\r
74 if (tgaHead.PixelDepth==32) AlphaCreate(); // Image has alpha channel
\r
75 #endif //CXIMAGE_SUPPORT_ALPHA
\r
77 if (!IsValid()) cx_throw("TGA Create failed");
\r
79 if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding
\r
81 if (tgaHead.CmapType != 0){ // read the palette
\r
83 hFile->Read(pal,tgaHead.CmapLength*sizeof(rgb_color), 1);
\r
84 for (int i=0;i<tgaHead.CmapLength; i++) SetPaletteColor((BYTE)i,pal[i].b,pal[i].g,pal[i].r);
\r
87 if (tgaHead.ImageType == TGA_Mono || tgaHead.ImageType == TGA_RLEMono)
\r
90 // Bits 4 & 5 of the Image Descriptor byte control the ordering of the pixels.
\r
91 bool bXReversed = ((tgaHead.ImagDesc & 16) == 16);
\r
92 bool bYReversed = ((tgaHead.ImagDesc & 32) == 32);
\r
94 CImageIterator iter(this);
\r
95 BYTE rleLeftover = 255; //for images with illegal packet boundary
\r
97 for (int y=0; y < tgaHead.ImageHeight; y++){
\r
99 if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding
\r
101 if (hFile == NULL || hFile->Eof()) cx_throw("corrupted TGA");
\r
103 if (bYReversed) pDest = iter.GetRow(tgaHead.ImageHeight-y-1);
\r
104 else pDest = iter.GetRow(y);
\r
106 if (bCompressed) rleLeftover = ExpandCompressedLine(pDest,&tgaHead,hFile,tgaHead.ImageWidth,y,rleLeftover);
\r
107 else ExpandUncompressedLine (pDest,&tgaHead,hFile,tgaHead.ImageWidth,y,0);
\r
110 if (bXReversed) Mirror();
\r
112 #if CXIMAGE_SUPPORT_ALPHA
\r
113 if (bYReversed && tgaHead.PixelDepth==32) AlphaFlip(); //<lioucr>
\r
114 #endif //CXIMAGE_SUPPORT_ALPHA
\r
117 if (strcmp(message,"")) strncpy(info.szLastError,message,255);
\r
122 ////////////////////////////////////////////////////////////////////////////////
\r
123 #endif //CXIMAGE_SUPPORT_DECODE
\r
124 ////////////////////////////////////////////////////////////////////////////////
\r
125 #if CXIMAGE_SUPPORT_ENCODE
\r
126 ////////////////////////////////////////////////////////////////////////////////
\r
127 bool CxImageTGA::Encode(CxFile * hFile)
\r
129 if (EncodeSafeCheck(hFile)) return false;
\r
131 if (head.biBitCount<8){
\r
132 strcpy(info.szLastError,"Bit depth must be 8 or 24");
\r
138 tgaHead.IdLength = 0; // Image ID Field Length
\r
139 tgaHead.CmapType = GetPalette()!=0; // Color Map Type
\r
140 tgaHead.ImageType = (head.biBitCount == 8) ? (BYTE)TGA_Map : (BYTE)TGA_RGB; // Image Type
\r
142 tgaHead.CmapIndex=0; // First Entry Index
\r
143 tgaHead.CmapLength=(head.biBitCount == 8) ? 256 : 0; // Color Map Length
\r
144 tgaHead.CmapEntrySize=(head.biBitCount == 8) ? (BYTE)24 : (BYTE)0; // Color Map Entry Size
\r
146 tgaHead.X_Origin=0; // X-origin of Image
\r
147 tgaHead.Y_Origin=0; // Y-origin of Image
\r
148 tgaHead.ImageWidth=(WORD)head.biWidth; // Image Width
\r
149 tgaHead.ImageHeight=(WORD)head.biHeight; // Image Height
\r
150 tgaHead.PixelDepth=(BYTE)head.biBitCount; // Pixel Depth
\r
151 tgaHead.ImagDesc=0; // Image Descriptor
\r
153 if (pAlpha && head.biBitCount==24) tgaHead.PixelDepth=32;
\r
156 hFile->Write(&tgaHead,sizeof(TGAHEADER),1);
\r
159 if (head.biBitCount==8){
\r
160 rgb_color pal[256];
\r
161 RGBQUAD* ppal = GetPalette();
\r
162 for (int i=0;i<256; i++){
\r
163 pal[i].r = ppal[i].rgbBlue;
\r
164 pal[i].g = ppal[i].rgbGreen;
\r
165 pal[i].b = ppal[i].rgbRed;
\r
167 hFile->Write(&pal,256*sizeof(rgb_color),1);
\r
170 CImageIterator iter(this);
\r
172 if (pAlpha==0 || head.biBitCount==8){
\r
173 for (int y=0; y < tgaHead.ImageHeight; y++){
\r
174 pDest = iter.GetRow(y);
\r
175 hFile->Write(pDest,tgaHead.ImageWidth * (head.biBitCount >> 3),1);
\r
178 pDest = (BYTE*)malloc(4*tgaHead.ImageWidth);
\r
180 for (int y=0; y < tgaHead.ImageHeight; y++){
\r
181 for(int x=0, x4=0;x<tgaHead.ImageWidth;x++, x4+=4){
\r
182 c = BlindGetPixelColor(x,y);
\r
183 pDest[x4+0]=c.rgbBlue;
\r
184 pDest[x4+1]=c.rgbGreen;
\r
185 pDest[x4+2]=c.rgbRed;
\r
186 #if CXIMAGE_SUPPORT_ALPHA // <vho>
\r
187 pDest[x4+3]=AlphaGet(x,y);
\r
190 #endif //CXIMAGE_SUPPORT_ALPHA
\r
192 hFile->Write(pDest,4*tgaHead.ImageWidth,1);
\r
198 ////////////////////////////////////////////////////////////////////////////////
\r
199 #endif // CXIMAGE_SUPPORT_ENCODE
\r
200 ////////////////////////////////////////////////////////////////////////////////
\r
201 BYTE CxImageTGA::ExpandCompressedLine(BYTE* pDest,TGAHEADER* ptgaHead,CxFile *hFile,int width, int y, BYTE rleLeftover)
\r
205 for (int x=0; x<width; ){
\r
206 if (rleLeftover != 255){
\r
210 hFile->Read(&rle,1,1);
\r
212 if (rle & 128) { // RLE-Encoded packet
\r
213 rle -= 127; // Calculate real repeat count.
\r
214 if ((x+rle)>width){
\r
215 rleLeftover = (BYTE)(128 + (rle - (width - x) - 1));
\r
216 filePos = hFile->Tell();
\r
217 rle = (BYTE)(width - x);
\r
219 switch (ptgaHead->PixelDepth)
\r
223 hFile->Read(&color,4,1);
\r
224 for (int ix = 0; ix < rle; ix++){
\r
225 memcpy(&pDest[3*ix],&color,3);
\r
226 #if CXIMAGE_SUPPORT_ALPHA // <vho>
\r
227 AlphaSet(ix+x,y,color.rgbReserved);
\r
228 #endif //CXIMAGE_SUPPORT_ALPHA
\r
234 hFile->Read(&triple,3,1);
\r
235 for (int ix = 0; ix < rle; ix++) memcpy(&pDest[3*ix],&triple,3);
\r
241 hFile->Read(&pixel,2,1);
\r
243 triple.r = (BYTE)(( pixel & 0x1F ) * 8); // red
\r
244 triple.g = (BYTE)(( pixel >> 2 ) & 0x0F8); // green
\r
245 triple.b = (BYTE)(( pixel >> 7 ) & 0x0F8); // blue
\r
246 for (int ix = 0; ix < rle; ix++){
\r
247 memcpy(&pDest[3*ix],&triple,3);
\r
253 hFile->Read(&pixel,1,1);
\r
254 for (int ix = 0; ix < rle; ix++) pDest[ix] = pixel;
\r
257 if (rleLeftover!=255) hFile->Seek(filePos, SEEK_SET);
\r
258 } else { // Raw packet
\r
259 rle += 1; // Calculate real repeat count.
\r
260 if ((x+rle)>width){
\r
261 rleLeftover = (BYTE)(rle - (width - x) - 1);
\r
262 rle = (BYTE)(width - x);
\r
264 ExpandUncompressedLine(pDest,ptgaHead,hFile,rle,y,x);
\r
266 if (head.biBitCount == 24) pDest += rle*3; else pDest += rle;
\r
269 return rleLeftover;
\r
271 ////////////////////////////////////////////////////////////////////////////////
\r
272 void CxImageTGA::ExpandUncompressedLine(BYTE* pDest,TGAHEADER* ptgaHead,CxFile *hFile,int width, int y, int xoffset)
\r
274 switch (ptgaHead->PixelDepth){
\r
276 hFile->Read(pDest,width,1);
\r
282 for (int x=0; x<width; x++){
\r
283 hFile->Read(&pixel,2,1);
\r
284 *dst++ = (BYTE)(( pixel & 0x1F ) * 8); // blue
\r
285 *dst++ = (BYTE)(( pixel >> 2 ) & 0x0F8); // green
\r
286 *dst++ = (BYTE)(( pixel >> 7 ) & 0x0F8); // red
\r
291 hFile->Read(pDest,3*width,1);
\r
295 for (int x=0; x<width; x++){
\r
297 hFile->Read(&pixel,4,1);
\r
298 *dst++ = pixel.rgbBlue;
\r
299 *dst++ = pixel.rgbGreen;
\r
300 *dst++ = pixel.rgbRed;
\r
301 #if CXIMAGE_SUPPORT_ALPHA // <vho>
\r
302 AlphaSet(x+xoffset,y,pixel.rgbReserved); //alpha
\r
303 #endif //CXIMAGE_SUPPORT_ALPHA
\r
309 ////////////////////////////////////////////////////////////////////////////////
\r
310 void CxImageTGA::tga_toh(TGAHEADER* p)
\r
312 p->CmapIndex = ntohs(p->CmapIndex);
\r
313 p->CmapLength = ntohs(p->CmapLength);
\r
314 p->X_Origin = ntohs(p->X_Origin);
\r
315 p->Y_Origin = ntohs(p->Y_Origin);
\r
316 p->ImageWidth = ntohs(p->ImageWidth);
\r
317 p->ImageHeight = ntohs(p->ImageHeight);
\r
319 ////////////////////////////////////////////////////////////////////////////////
\r
320 #endif // CXIMAGE_SUPPORT_TGA
\r