3
* Purpose: Platform Independent TGA Image Class Loader and Writer
4
* 05/Jan/2001 Davide Pizzolato - www.xdp.it
5
* CxImage version 5.99c 17/Oct/2004
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
bool CxImageTGA::Decode(CxFile *hFile)
28
if (hFile == NULL) return false;
34
if (hFile->Read(&tgaHead,sizeof(tgaHead),1)==0)
38
switch (tgaHead.ImageType){
50
throw "Unknown TGA image type";
53
if (tgaHead.ImageWidth==0 || tgaHead.ImageHeight==0 || tgaHead.PixelDepth==0 || tgaHead.CmapLength>256)
54
throw "bad TGA header";
56
if (tgaHead.PixelDepth!=8 && tgaHead.PixelDepth!=15 && tgaHead.PixelDepth!=16 && tgaHead.PixelDepth!=24 && tgaHead.PixelDepth!=32)
57
throw "bad TGA header";
59
if (tgaHead.IdLength>0) hFile->Seek(tgaHead.IdLength,SEEK_CUR); //skip descriptor
61
Create(tgaHead.ImageWidth, tgaHead.ImageHeight, tgaHead.PixelDepth, CXIMAGE_FORMAT_TGA);
62
#if CXIMAGE_SUPPORT_ALPHA // <vho>
63
if (tgaHead.PixelDepth==32) AlphaCreate(); // Image has alpha channel
64
#endif //CXIMAGE_SUPPORT_ALPHA
66
if (!IsValid()) throw "TGA Create failed";
68
if (info.nEscape) throw "Cancelled"; // <vho> - cancel decoding
70
if (tgaHead.CmapType != 0){ // read the palette
72
hFile->Read(pal,tgaHead.CmapLength*sizeof(rgb_color), 1);
73
for (int i=0;i<tgaHead.CmapLength; i++) SetPaletteColor((BYTE)i,pal[i].b,pal[i].g,pal[i].r);
76
if (tgaHead.ImageType == TGA_Mono || tgaHead.ImageType == TGA_RLEMono)
79
// Bits 4 & 5 of the Image Descriptor byte control the ordering of the pixels.
80
bool bXReversed = ((tgaHead.ImagDesc & 16) == 16);
81
bool bYReversed = ((tgaHead.ImagDesc & 32) == 32);
83
CImageIterator iter(this);
84
BYTE rleLeftover = 255; //for images with illegal packet boundary
86
for (int y=0; y < tgaHead.ImageHeight; y++){
88
if (info.nEscape) throw "Cancelled"; // <vho> - cancel decoding
90
if (hFile == NULL || hFile->Eof()) throw "corrupted TGA";
92
if (bYReversed) pDest = iter.GetRow(tgaHead.ImageHeight-y-1);
93
else pDest = iter.GetRow(y);
95
if (bCompressed) rleLeftover = ExpandCompressedLine(pDest,&tgaHead,hFile,tgaHead.ImageWidth,y,rleLeftover);
96
else ExpandUncompressedLine (pDest,&tgaHead,hFile,tgaHead.ImageWidth,y,0);
99
if (bXReversed) Mirror();
101
#if CXIMAGE_SUPPORT_ALPHA
102
if (bYReversed && tgaHead.PixelDepth==32) AlphaFlip(); //<lioucr>
103
#endif //CXIMAGE_SUPPORT_ALPHA
105
} catch (const char *message) {
106
strncpy(info.szLastError,message,255);
111
////////////////////////////////////////////////////////////////////////////////
112
#if CXIMAGE_SUPPORT_ENCODE
113
////////////////////////////////////////////////////////////////////////////////
114
bool CxImageTGA::Encode(CxFile * hFile)
116
if (EncodeSafeCheck(hFile)) return false;
118
if (head.biBitCount<8){
119
strcpy(info.szLastError,"Bit depth must be 8 or 24");
125
tgaHead.IdLength = 0; // Image ID Field Length
126
tgaHead.CmapType = GetPalette()!=0; // Color Map Type
127
tgaHead.ImageType = (head.biBitCount == 8) ? (BYTE)TGA_Map : (BYTE)TGA_RGB; // Image Type
129
tgaHead.CmapIndex=0; // First Entry Index
130
tgaHead.CmapLength=(head.biBitCount == 8) ? 256 : 0; // Color Map Length
131
tgaHead.CmapEntrySize=(head.biBitCount == 8) ? (BYTE)24 : (BYTE)0; // Color Map Entry Size
133
tgaHead.X_Origin=0; // X-origin of Image
134
tgaHead.Y_Origin=0; // Y-origin of Image
135
tgaHead.ImageWidth=(WORD)head.biWidth; // Image Width
136
tgaHead.ImageHeight=(WORD)head.biHeight; // Image Height
137
tgaHead.PixelDepth=(BYTE)head.biBitCount; // Pixel Depth
138
tgaHead.ImagDesc=0; // Image Descriptor
140
if (pAlpha && head.biBitCount==24) tgaHead.PixelDepth=32;
142
hFile->Write(&tgaHead,sizeof(TGAHEADER),1);
144
if (head.biBitCount==8){
146
RGBQUAD* ppal = GetPalette();
147
for (int i=0;i<256; i++){
148
pal[i].r = ppal[i].rgbBlue;
149
pal[i].g = ppal[i].rgbGreen;
150
pal[i].b = ppal[i].rgbRed;
152
hFile->Write(&pal,256*sizeof(rgb_color),1);
155
CImageIterator iter(this);
157
if (pAlpha==0 || head.biBitCount==8){
158
for (int y=0; y < tgaHead.ImageHeight; y++){
159
pDest = iter.GetRow(y);
160
hFile->Write(pDest,tgaHead.ImageWidth * (head.biBitCount >> 3),1);
163
pDest = (BYTE*)malloc(4*tgaHead.ImageWidth);
165
for (int y=0; y < tgaHead.ImageHeight; y++){
166
for(int x=0, x4=0;x<tgaHead.ImageWidth;x++, x4+=4){
167
c=GetPixelColor(x,y);
168
pDest[x4+0]=c.rgbBlue;
169
pDest[x4+1]=c.rgbGreen;
170
pDest[x4+2]=c.rgbRed;
171
#if CXIMAGE_SUPPORT_ALPHA // <vho>
172
pDest[x4+3]=(BYTE)((AlphaGet(x,y)*info.nAlphaMax)/255);
175
#endif //CXIMAGE_SUPPORT_ALPHA
177
hFile->Write(pDest,4*tgaHead.ImageWidth,1);
183
////////////////////////////////////////////////////////////////////////////////
184
#endif // CXIMAGE_SUPPORT_ENCODE
185
////////////////////////////////////////////////////////////////////////////////
186
BYTE CxImageTGA::ExpandCompressedLine(BYTE* pDest,TGAHEADER* ptgaHead,CxFile *hFile,int width, int y, BYTE rleLeftover)
191
for (int x=0; x<width; ){
192
if (rleLeftover != 255){
196
hFile->Read(&rle,1,1);
198
if (rle & 128) { // RLE-Encoded packet
199
rle -= 127; // Calculate real repeat count.
201
rleLeftover = 128 + (rle - (width - x) - 1);
202
filePos = hFile->Tell();
205
switch (ptgaHead->PixelDepth)
209
hFile->Read(&color,4,1);
210
for (int ix = 0; ix < rle; ix++){
211
memcpy(&pDest[3*ix],&color,3);
212
#if CXIMAGE_SUPPORT_ALPHA // <vho>
213
AlphaSet(ix+x,y,color.rgbReserved);
214
#endif //CXIMAGE_SUPPORT_ALPHA
220
hFile->Read(&triple,3,1);
221
for (int ix = 0; ix < rle; ix++) memcpy(&pDest[3*ix],&triple,3);
227
hFile->Read(&pixel,2,1);
229
triple.r = (BYTE)(( pixel & 0x1F ) * 8); // red
230
triple.g = (BYTE)(( pixel >> 2 ) & 0x0F8); // green
231
triple.b = (BYTE)(( pixel >> 7 ) & 0x0F8); // blue
232
for (int ix = 0; ix < rle; ix++){
233
memcpy(&pDest[3*ix],&triple,3);
239
hFile->Read(&pixel,1,1);
240
for (int ix = 0; ix < rle; ix++) pDest[ix] = pixel;
243
if (rleLeftover!=255) hFile->Seek(filePos, SEEK_SET);
244
} else { // Raw packet
245
rle += 1; // Calculate real repeat count.
247
rleLeftover = rle - (width - x) - 1;
250
ExpandUncompressedLine(pDest,ptgaHead,hFile,rle,y,x);
252
if (head.biBitCount == 24) pDest += rle*3; else pDest += rle;
258
////////////////////////////////////////////////////////////////////////////////
259
void CxImageTGA::ExpandUncompressedLine(BYTE* pDest,TGAHEADER* ptgaHead,CxFile *hFile,int width, int y, int xoffset)
262
switch (ptgaHead->PixelDepth){
264
hFile->Read(pDest,width,1);
270
for (int x=0; x<width; x++){
271
hFile->Read(&pixel,2,1);
272
*dst++ = (BYTE)(( pixel & 0x1F ) * 8); // blue
273
*dst++ = (BYTE)(( pixel >> 2 ) & 0x0F8); // green
274
*dst++ = (BYTE)(( pixel >> 7 ) & 0x0F8); // red
279
hFile->Read(pDest,3*width,1);
283
for (int x=0; x<width; x++){
285
hFile->Read(&pixel,4,1);
286
*dst++ = pixel.rgbBlue;
287
*dst++ = pixel.rgbGreen;
288
*dst++ = pixel.rgbRed;
289
#if CXIMAGE_SUPPORT_ALPHA // <vho>
290
AlphaSet(x+xoffset,y,pixel.rgbReserved); //alpha
291
#endif //CXIMAGE_SUPPORT_ALPHA
298
////////////////////////////////////////////////////////////////////////////////
299
#endif // CXIMAGE_SUPPORT_TGA