]> Creatis software - clitk.git/blob - utilities/CxImage/ximatga.cpp
b137126c4d1d7c154206651278c09083ab7e08ce
[clitk.git] / utilities / CxImage / ximatga.cpp
1 /*\r
2  * File:        ximatga.cpp\r
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
6  */\r
7 \r
8 #include "ximatga.h"\r
9 \r
10 #if CXIMAGE_SUPPORT_TGA\r
11 \r
12 #include "ximaiter.h"\r
13 \r
14 // Definitions for image types.\r
15 #define TGA_Null 0\r
16 #define TGA_Map 1\r
17 #define TGA_RGB 2\r
18 #define TGA_Mono 3\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
24 \r
25 ////////////////////////////////////////////////////////////////////////////////\r
26 #if CXIMAGE_SUPPORT_DECODE\r
27 ////////////////////////////////////////////////////////////////////////////////\r
28 bool CxImageTGA::Decode(CxFile *hFile)\r
29 {\r
30         if (hFile == NULL) return false;\r
31 \r
32         TGAHEADER tgaHead;\r
33 \r
34   cx_try\r
35   {\r
36         if (hFile->Read(&tgaHead,sizeof(tgaHead),1)==0)\r
37                 cx_throw("Not a TGA");\r
38 \r
39         tga_toh(&tgaHead);\r
40 \r
41         bool bCompressed;\r
42         switch (tgaHead.ImageType){\r
43         case TGA_Map:\r
44         case TGA_RGB:\r
45         case TGA_Mono:\r
46                 bCompressed = false;\r
47                 break;\r
48         case TGA_RLEMap:\r
49         case TGA_RLERGB:\r
50         case TGA_RLEMono:\r
51                 bCompressed = true;\r
52                 break;\r
53         default:\r
54                 cx_throw("Unknown TGA image type");\r
55         }\r
56 \r
57         if (tgaHead.ImageWidth==0 || tgaHead.ImageHeight==0 || tgaHead.PixelDepth==0 || tgaHead.CmapLength>256)\r
58                 cx_throw("bad TGA header");\r
59 \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
62 \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
67                 return true;\r
68         }\r
69 \r
70         if (tgaHead.IdLength>0) hFile->Seek(tgaHead.IdLength,SEEK_CUR); //skip descriptor\r
71 \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
76 \r
77         if (!IsValid()) cx_throw("TGA Create failed");\r
78         \r
79         if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding\r
80 \r
81         if (tgaHead.CmapType != 0){ // read the palette\r
82                 rgb_color pal[256];\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
85         }\r
86 \r
87         if (tgaHead.ImageType == TGA_Mono || tgaHead.ImageType == TGA_RLEMono)\r
88                 SetGrayPalette();\r
89 \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
93 \r
94     CImageIterator iter(this);\r
95         BYTE rleLeftover = 255; //for images with illegal packet boundary \r
96         BYTE* pDest;\r
97     for (int y=0; y < tgaHead.ImageHeight; y++){\r
98 \r
99                 if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding\r
100 \r
101                 if (hFile == NULL || hFile->Eof()) cx_throw("corrupted TGA");\r
102 \r
103                 if (bYReversed) pDest = iter.GetRow(tgaHead.ImageHeight-y-1);\r
104                 else pDest = iter.GetRow(y);\r
105 \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
108     }\r
109 \r
110         if (bXReversed) Mirror();\r
111 \r
112 #if CXIMAGE_SUPPORT_ALPHA\r
113         if (bYReversed && tgaHead.PixelDepth==32) AlphaFlip(); //<lioucr>\r
114 #endif //CXIMAGE_SUPPORT_ALPHA\r
115 \r
116   } cx_catch {\r
117         if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
118         return false;\r
119   }\r
120     return true;\r
121 }\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
128 {\r
129         if (EncodeSafeCheck(hFile)) return false;\r
130 \r
131         if (head.biBitCount<8){\r
132                 strcpy(info.szLastError,"Bit depth must be 8 or 24");\r
133                 return false;\r
134         }\r
135 \r
136         TGAHEADER tgaHead;\r
137 \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
141 \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
145 \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
152 \r
153         if (pAlpha && head.biBitCount==24) tgaHead.PixelDepth=32; \r
154 \r
155         tga_toh(&tgaHead);\r
156         hFile->Write(&tgaHead,sizeof(TGAHEADER),1);\r
157         tga_toh(&tgaHead);\r
158 \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
166                 }\r
167                 hFile->Write(&pal,256*sizeof(rgb_color),1);\r
168         }\r
169         \r
170         CImageIterator iter(this);\r
171         BYTE* pDest;\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
176                 }\r
177         } else {\r
178                 pDest = (BYTE*)malloc(4*tgaHead.ImageWidth);\r
179                 RGBQUAD c;\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
188 #else\r
189                                 pDest[x4+3]=0;\r
190 #endif //CXIMAGE_SUPPORT_ALPHA\r
191                         }\r
192                         hFile->Write(pDest,4*tgaHead.ImageWidth,1);\r
193                 }\r
194                 free(pDest);\r
195         }\r
196         return true;\r
197 }\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
202 {\r
203         BYTE rle;\r
204         long filePos=0;\r
205         for (int x=0; x<width; ){\r
206                 if (rleLeftover != 255){\r
207             rle = rleLeftover;\r
208             rleLeftover = 255;\r
209         } else {\r
210                         hFile->Read(&rle,1,1);\r
211                 }\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
218                         }\r
219                         switch (ptgaHead->PixelDepth)\r
220                         {\r
221                         case 32: {\r
222                                 RGBQUAD color;\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
229                                 }\r
230                                 break;\r
231                                          } \r
232                         case 24: {\r
233                                 rgb_color triple;\r
234                                 hFile->Read(&triple,3,1);\r
235                                 for (int ix = 0; ix < rle; ix++) memcpy(&pDest[3*ix],&triple,3);\r
236                                 break;\r
237                                          }\r
238                         case 15:\r
239                         case 16: {\r
240                                 WORD pixel;\r
241                                 hFile->Read(&pixel,2,1);\r
242                                 rgb_color triple;\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
248                                 }\r
249                                 break;\r
250                                          }\r
251                         case 8: {\r
252                                 BYTE pixel;\r
253                                 hFile->Read(&pixel,1,1);\r
254                                 for (int ix = 0; ix < rle; ix++) pDest[ix] = pixel;\r
255                                         }\r
256                         }\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
263                         }\r
264                         ExpandUncompressedLine(pDest,ptgaHead,hFile,rle,y,x);\r
265                 }\r
266                 if (head.biBitCount == 24)      pDest += rle*3; else pDest += rle;\r
267                 x += rle;\r
268         }\r
269         return rleLeftover;\r
270 }\r
271 ////////////////////////////////////////////////////////////////////////////////\r
272 void CxImageTGA::ExpandUncompressedLine(BYTE* pDest,TGAHEADER* ptgaHead,CxFile *hFile,int width, int y, int xoffset)\r
273 {\r
274         switch (ptgaHead->PixelDepth){\r
275         case 8:\r
276                 hFile->Read(pDest,width,1);\r
277                 break;\r
278         case 15:\r
279         case 16:{\r
280                 BYTE* dst=pDest;\r
281                 WORD pixel;\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
287                 }\r
288                 break;\r
289                         }\r
290         case 24:\r
291                 hFile->Read(pDest,3*width,1);\r
292                 break;\r
293         case 32:{\r
294                 BYTE* dst=pDest;\r
295                 for (int x=0; x<width; x++){\r
296                         RGBQUAD pixel;\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
304                 }\r
305                 break;\r
306                         }\r
307         }\r
308 }\r
309 ////////////////////////////////////////////////////////////////////////////////\r
310 void CxImageTGA::tga_toh(TGAHEADER* p)\r
311 {\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
318 }\r
319 ////////////////////////////////////////////////////////////////////////////////\r
320 #endif  // CXIMAGE_SUPPORT_TGA\r
321 \r