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