source: liacs/MIR2010/SourceCode/cximage/ximatga.cpp@ 393

Last change on this file since 393 was 95, checked in by Rick van der Zwet, 15 years ago

Bad boy, improper move of directory

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