]> icculus.org git repositories - taylor/freespace2.git/blob - src/tgautils/tgautils.cpp
Initial revision
[taylor/freespace2.git] / src / tgautils / tgautils.cpp
1 /*
2  * $Logfile: /Freespace2/code/TgaUtils/TgaUtils.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  *
8  * $Log$
9  * Revision 1.1  2002/05/03 03:28:11  root
10  * Initial revision
11  *
12  * 
13  * 7     7/13/99 1:16p Dave
14  * 32 bit support. Whee!
15  * 
16  * 6     3/20/99 3:46p Dave
17  * Added support for model-based background nebulae. Added 3 new
18  * sexpressions.
19  * 
20  * 5     12/03/98 9:39a Dave
21  * Removed bogus tga code assert?
22  * 
23  * 4     12/02/98 5:47p Dave
24  * Put in interface xstr code. Converted barracks screen to new format.
25  * 
26  * 3     12/01/98 5:54p Dave
27  * Simplified the way pixel data is swizzled. Fixed tga bitmaps to work
28  * properly in D3D and Glide.
29  * 
30  * 2     12/01/98 4:46p Dave
31  * Put in targa bitmap support (16 bit).
32  *  
33  * $NoKeywords: $
34  */
35
36 #include <stdio.h>
37 #include <string.h>
38
39 #include "tgautils.h"
40 #include "cfile.h"
41 #include "bmpman.h"
42 #include "palman.h"
43
44 // -----------------
45 //
46 // Defines
47 //
48 // -----------------
49
50 #define MAX_TARGA_RUN_LENGTH_PACKET 128
51 #define TARGA_HEADER_LENGTH 18
52 #define ULORIGIN                (header.image_descriptor & 0x20)
53
54 // -----------------
55 //
56 // Structures
57 //
58 // -----------------
59
60 typedef struct targa_header {
61         ubyte id_length;
62         ubyte color_map_type;
63         ubyte image_type;
64         short cmap_start;
65         short cmap_length;
66         ubyte cmap_depth;
67         short xoffset;
68         short yoffset;
69         short width;
70         short height;
71         ubyte pixel_depth;
72         ubyte image_descriptor;
73 } targa_header;
74
75 // -----------------
76 //
77 // Internal Functions
78 //
79 // -----------------
80
81
82 // copy from one pixel buffer to another
83 //
84 // to - pointer to dest. buffet
85 // from - pointer to source buffer
86 // pixels - number of pixels to copy
87 // fromsize - source pixel size
88 // tosize - dest. pixel size
89 //
90 // returns - number of pixels copied to destination
91 //
92 static int targa_copy_data(char *to, char *from, int pixels, int fromsize, int tosize)
93 {
94         if ( (fromsize == 2) && (tosize==2) )   {
95                 // Flip the alpha bit on 1555 format
96                 ushort *src, *dst;
97
98                 src = (ushort *)from;
99                 dst = (ushort *)from;
100                 for (int i=0; i<pixels; i++ )   {
101                         *dst++ = (ushort)((*src++) ^ 0x8000);           // Flip the transparency bit
102                 }
103                 return tosize*pixels;
104         } else if ( (fromsize == 2) && (tosize == 3) )  {
105                 ushort *src;
106
107                 src = (ushort *)from;
108                 for (int i=0; i<pixels; i++ )   {                       
109                         ushort pixel = *src++;
110
111                         *to++ = (ubyte)((pixel & 0x1f) * 8);
112                         *to++ = (ubyte)(((pixel >> 5) & 63) * 4);
113                         *to++ = (ubyte)(((pixel >> 11) & 0x1f) * 8);
114                 }
115                 return tosize*pixels;
116         } else {
117                 Assert(fromsize == tosize);
118                 memcpy(to, from, pixels * fromsize);
119                 return tosize*pixels;
120         }
121 }
122
123 //      targa_pixels_equal -- Test if two pixels are identical
124 //
125 // pix1 - first pixel data
126 // pix2 - second pixel data
127 // pixbytes - number of bytes per pixel
128 //
129 // returns - 0 if No Match, else 1 if Match
130 static int targa_pixels_equal(char *pix1, char *pix2, int pixbytes)
131 {
132         do      {
133                 if ( *pix1++ != *pix2++ ) {
134                         return 0;
135                 }
136         } while ( --pixbytes > 0 );
137
138         return 1;
139 }
140
141 //      Perform targa RLE on the input data
142 //
143 // out - Buffer to write it out to
144 // in - Buffer to compress
145 // outsize - Number of bytes in output buffer
146 // pixsize - Number of bytes in input pixel
147 // bytecount - Number of bytes input
148 //
149 // returns -  size of compressed data
150 //
151 int targa_compress(char *out, char *in, int outsize, int pixsize, int bytecount)
152 {
153         int pixcount;           // number of pixels in the current packet
154         char *inputpixel=NULL;  // current input pixel position
155         char *matchpixel=NULL;  // pixel value to match for a run
156         char *flagbyte=NULL;            // location of last flag byte to set
157         int rlcount;            // current count in r.l. string 
158         int rlthresh;           // minimum valid run length
159         char *copyloc;          // location to begin copying at
160
161         // set the threshold -- the minimum valid run length
162
163         if (outsize == 1) {
164                 rlthresh = 2;                                   // for 8bpp, require a 2 pixel span before rle'ing
165         } else {
166                 rlthresh = 1;                   
167         }
168
169         // set the first pixel up
170
171         flagbyte = out; // place to put next flag if run
172         inputpixel = in;
173         pixcount = 1;
174         rlcount = 0;
175         copyloc = (char *)0;
176
177         // loop till data processing complete
178         do      {
179
180                 // if we have accumulated a 128-byte packet, process it
181                 if ( pixcount == 129 )  {
182                         *flagbyte = 127;
183
184                         // set the run flag if this is a run
185
186                         if ( rlcount >= rlthresh )      {
187                                         *flagbyte |= 0x80;
188                                         pixcount = 2;
189                         }
190
191                         // copy the data into place
192                         ++flagbyte;
193                         flagbyte += targa_copy_data(flagbyte, copyloc, pixcount-1, pixsize, outsize);
194                         pixcount = 1;
195
196                         // set up for next packet
197                         continue;
198                 }
199
200                 // if zeroth byte, handle as special case
201                 if ( pixcount == 1 )    {
202                         rlcount = 0;
203                         copyloc = inputpixel;           /* point to 1st guy in packet */
204                         matchpixel = inputpixel;        /* set pointer to pix to match */
205                         pixcount = 2;
206                         inputpixel += pixsize;
207                         continue;
208                 }
209
210                 // assembling a packet -- look at next pixel
211
212                 // current pixel == match pixel?
213                 if ( targa_pixels_equal(inputpixel, matchpixel, outsize) )      {
214
215                         //      establishing a run of enough length to
216                         //      save space by doing it
217                         //              -- write the non-run length packet
218                         //              -- start run-length packet
219
220                         if ( ++rlcount == rlthresh )    {
221                                 
222                                 //      close a non-run packet
223                                 
224                                 if ( pixcount > (rlcount+1) )   {
225                                         // write out length and do not set run flag
226
227                                         *flagbyte++ = (char)(pixcount - 2 - rlthresh);
228
229                                         flagbyte += targa_copy_data(flagbyte, copyloc, (pixcount-1-rlcount), pixsize, outsize);
230
231                                         copyloc = inputpixel;
232                                         pixcount = rlcount + 1;
233                                 }
234                         }
235                 } else {
236
237                         // no match -- either break a run or continue without one
238                         //      if a run exists break it:
239                         //              write the bytes in the string (outsize+1)
240                         //              start the next string
241
242                         if ( rlcount >= rlthresh )      {
243
244                                 *flagbyte++ = (char)(0x80 | rlcount);
245                                 flagbyte += targa_copy_data(flagbyte, copyloc, 1, pixsize, outsize);
246                                 pixcount = 1;
247                                 continue;
248                         } else {
249
250                                 //      not a match and currently not a run
251                                 //              - save the current pixel
252                                 //              - reset the run-length flag
253                                 rlcount = 0;
254                                 matchpixel = inputpixel;
255                         }
256                 }
257                 pixcount++;
258                 inputpixel += pixsize;
259         } while ( inputpixel < (in + bytecount));
260
261         // quit this buffer without loosing any data
262
263         if ( --pixcount >= 1 )  {
264                 *flagbyte = (char)(pixcount - 1);
265                 if ( rlcount >= rlthresh )      {
266                         *flagbyte |= 0x80;
267                         pixcount = 1;
268                 }
269
270                 // copy the data into place
271                 ++flagbyte;
272                 flagbyte += targa_copy_data(flagbyte, copyloc, pixcount, pixsize, outsize);
273         }
274         return(flagbyte-out);
275 }
276
277 // Reads a pixel of the specified bytes_per_pixel into memory and
278 // returns the number of bytes read into memory.
279 // NOTE : for Freespace2, this also swizzles data into the proper screen (NOT texture) format - just like
280 //        the pcxutils do.
281 // 
282 // dst - A pointer to the destination.  Must be at least 4 bytes long.
283 // targa_file - The file to read from.
284 // bytes_per_pixel - The bytes per pixel of the file.
285 // dest_size - bytes per pixel in destination (1 or 2. 1 == 8 bit paletted)
286 //
287 // returns - Number of byte read into memory
288 //
289 static void targa_read_pixel( int num_pixels, ubyte **dst, ubyte **src, int bytes_per_pixel, int dest_size )
290 {
291         int idx;
292         ushort pixel;
293         ubyte pal_index;
294         ubyte r, g, b;
295         ubyte al = 0;
296
297         for(idx=0; idx<num_pixels; idx++){
298                 // stuff the 16 bit pixel
299                 memcpy(&pixel, *src, bytes_per_pixel);
300                                                 
301                 // if the pixel is transparent, make it so...   
302                 if(((pixel & 0x7c00) == 0) && ((pixel & 0x03e0) == 0x03e0) && ((pixel & 0x001f) == 0)){
303                         r = b = 0;
304                         g = 255;
305                         al = 0;
306                         bm_set_components((ubyte*)&pixel, &r, &g, &b, &al);
307                 } else {
308                         // get the 8 bit r, g, and b values
309                         r = (ubyte)(((pixel & 0x7c00) >> 10) * 8);
310                         g = (ubyte)(((pixel & 0x03e0) >> 5) * 8);
311                         b = (ubyte)((pixel & 0x001f) * 8);
312                         al = 1;
313
314                         // now stuff these back, swizzling properly
315                         pixel = 0;
316                         bm_set_components((ubyte*)&pixel, &r, &g, &b, &al);
317                 }
318
319                 // 16 bit destination
320                 if(dest_size == 2){
321                         // stuff the final pixel                
322                         memcpy( *dst, &pixel, bytes_per_pixel );                        
323                 }
324                 // 8 bit destination 
325                 else {
326                         pal_index = (ubyte)palette_find((int)r, (int)g, (int)b);
327                         **dst = pal_index;                      
328                 }
329
330                 // next pixel
331                 (*dst) += dest_size;
332                 (*src) += bytes_per_pixel;              
333         }
334 }
335
336 // -----------------
337 //
338 // External Functions
339 //
340 // -----------------
341
342 // Reads header information from the targa file into the bitmap pointer
343 // 
344 // filename - name of the targa bitmap file
345 // w - (output) width of the bitmap
346 // h - (output) height of the bitmap
347 // bpp - (output) bits per pixel of the bitmap
348 //
349 // returns - TARGA_ERROR_NONE if successful, otherwise error code
350 //
351 int targa_read_header(char *real_filename, int *w, int *h, int *bpp, ubyte *palette )
352 {       
353         targa_header header;
354         CFILE *targa_file;
355         char filename[MAX_FILENAME_LEN];
356                 
357         strcpy( filename, real_filename );
358         char *p = strchr( filename, '.' );
359         if ( p ) *p = 0;
360         strcat( filename, ".tga" );
361
362         targa_file = cfopen( filename , "rb" );
363         if ( !targa_file ){
364                 return TARGA_ERROR_READING;
365         }       
366
367         header.id_length = cfread_ubyte(targa_file);
368         // header.id_length=targa_file.read_char();
369
370         header.color_map_type = cfread_ubyte(targa_file);
371         // header.color_map_type=targa_file.read_char();
372
373         header.image_type = cfread_ubyte(targa_file);
374         // header.image_type=targa_file.read_char();
375
376         header.cmap_start = cfread_short(targa_file);
377         // header.cmap_start=targa_file.read_short();
378
379         header.cmap_length = cfread_short(targa_file);
380         // header.cmap_length=targa_file.read_short();
381
382         header.cmap_depth = cfread_ubyte(targa_file);
383         // header.cmap_depth=targa_file.read_char();
384
385         header.xoffset = cfread_short(targa_file);
386         // header.xoffset=targa_file.read_short();
387
388         header.yoffset = cfread_short(targa_file);
389         // header.yoffset=targa_file.read_short();
390
391         header.width = cfread_short(targa_file);
392         // header.width=targa_file.read_short();
393
394         header.height = cfread_short(targa_file);
395         // header.height=targa_file.read_short();
396
397         header.pixel_depth = cfread_ubyte(targa_file);
398         // header.pixel_depth=targa_file.read_char();
399
400         header.image_descriptor = cfread_ubyte(targa_file);
401         // header.image_descriptor=targa_file.read_char();
402
403         cfclose(targa_file);
404         targa_file = NULL;
405
406         *w = header.width;
407         *h = header.height;
408         *bpp = header.pixel_depth;
409
410         // only support 16 bit pixels
411         Assert(*bpp == 16);
412         if(*bpp != 16){
413                 return TARGA_ERROR_READING;
414         }
415         
416         return TARGA_ERROR_NONE;
417 }
418
419 // Uncompresses some RLE'd TGA data
420 //
421 // dst: pointer uncompressed destination.
422 // src: pointer to source rle'd data.
423 // bitmap_width: how many pixels to uncompress.
424 // bytes_per_pixel: bytes per pixel of the data.
425 //
426 // returns: number of input bytes processed.
427 //
428 int targa_uncompress( ubyte *dst, ubyte *src, int bitmap_width, int bytes_per_pixel, int dest_size )
429 {
430         ubyte *pixdata = dst;
431         ubyte *src_pixels = src;
432
433         int pixel_count = 0;         // Initialize pixel counter 
434
435         // Main decoding loop 
436         while (pixel_count < bitmap_width ) {
437
438                 // Get the pixel count 
439                 int run_count = *src_pixels++;
440
441                 // Make sure writing this next run will not overflow the buffer 
442                 Assert(pixel_count + (run_count & 0x7f) + 1 <= bitmap_width );
443                 
444                 // If the run is encoded... 
445                 if ( run_count & 0x80 ) {
446                         run_count &= ~0x80;              // Mask off the upper bit       
447
448                         // Update total pixel count 
449                         pixel_count += (run_count + 1);
450
451                         ubyte pixel_value[4];   // temporary
452                         ubyte *tmp = pixel_value;
453                         targa_read_pixel( 1, &tmp, &src_pixels, bytes_per_pixel, dest_size );
454
455                         // Write remainder of pixel run to buffer 'run_count' times 
456                         do {
457                                 memcpy( pixdata, pixel_value, dest_size );
458                                 pixdata += dest_size;
459                         } while (run_count--);
460
461                 } else {   // ...the run is unencoded (raw) 
462                         // Update total pixel count 
463                         pixel_count += (run_count + 1);
464
465                         // Read run_count pixels 
466                         targa_read_pixel(run_count+1, &pixdata, &src_pixels, bytes_per_pixel, dest_size );
467                 }
468         }
469
470         Assert( pixel_count == bitmap_width );
471
472         return src_pixels - src;
473 }
474
475
476 // Loads a Targa bitmap
477 // 
478 // filename - name of the targa file to load
479 // image_data - allocated storage for the bitmap
480 //
481 // returns - true if succesful, false otherwise
482 //
483 int targa_read_bitmap(char *real_filename, ubyte *image_data, ubyte *palette, int dest_size)
484 {
485         Assert(real_filename);
486         targa_header header;
487         CFILE *targa_file;
488         char filename[MAX_FILENAME_LEN];
489         ubyte r, g, b;
490                 
491         // open the file
492         strcpy( filename, real_filename );
493         char *p = strchr( filename, '.' );
494         if ( p ) *p = 0;
495         strcat( filename, ".tga" );
496
497         targa_file = cfopen( filename , "rb" );
498         if ( !targa_file ){
499                 return TARGA_ERROR_READING;
500         }               
501
502         header.id_length = cfread_ubyte(targa_file);
503         // header.id_length=targa_file.read_char();
504
505         header.color_map_type = cfread_ubyte(targa_file);
506         // header.color_map_type=targa_file.read_char();
507
508         header.image_type = cfread_ubyte(targa_file);
509         // header.image_type=targa_file.read_char();
510
511         header.cmap_start = cfread_short(targa_file);
512         // header.cmap_start=targa_file.read_short();
513
514         header.cmap_length = cfread_short(targa_file);
515         // header.cmap_length=targa_file.read_short();
516
517         header.cmap_depth = cfread_ubyte(targa_file);
518         // header.cmap_depth=targa_file.read_char();
519
520         header.xoffset = cfread_short(targa_file);
521         // header.xoffset=targa_file.read_short();
522
523         header.yoffset = cfread_short(targa_file);
524         // header.yoffset=targa_file.read_short();
525
526         header.width = cfread_short(targa_file);
527         // header.width=targa_file.read_short();
528
529         header.height = cfread_short(targa_file);
530         // header.height=targa_file.read_short();
531
532         header.pixel_depth = cfread_ubyte(targa_file);
533         // header.pixel_depth=targa_file.read_char();
534
535         header.image_descriptor = cfread_ubyte(targa_file);
536         // header.image_descriptor=targa_file.read_char();      
537
538         int bytes_per_pixel = (header.pixel_depth>>3);
539         // we're only allowing 2 bytes per pixel (16 bit compressed)
540         Assert(bytes_per_pixel == 2);
541         if(bytes_per_pixel != 2){
542                 cfclose(targa_file);
543                 return TARGA_ERROR_READING;
544         }
545
546         int xo, yo;
547         if ( header.image_descriptor & 0x10 )   {
548                 xo = 1;
549         } else {
550                 xo = 0;
551         }
552
553         if ( header.image_descriptor & 0x20 )   {
554                 yo = 1;
555         } else {
556                 yo = 0;
557         }               
558
559         // only accept 16 bit, compressed
560         if(header.pixel_depth!=16) {
561                 cfclose(targa_file);
562                 return TARGA_ERROR_READING;
563         }
564
565         /*
566         char test=char(header.image_descriptor&0xF);
567         if((test!=8)&&(test!=0)) {
568                 cfclose(targa_file);
569                 return TARGA_ERROR_READING;
570         }
571         */
572
573         if((header.image_type!=1)&&(header.image_type!=2)&&(header.image_type!=9)&&(header.image_type!=10)) {
574                 cfclose(targa_file);
575                 return TARGA_ERROR_READING;
576         }
577
578         // skip the Image ID field -- should not be needed
579         if(header.id_length>0) {
580                 if(cfseek(targa_file, header.id_length, CF_SEEK_SET)) {
581                         cfclose(targa_file);
582                         return TARGA_ERROR_READING;
583                 }
584         }
585
586         // read palette if one present.
587
588         if (header.color_map_type)      {                // non-zero indicates palette in the file
589                 Int3();
590
591                 // Determine the size of the color map
592                 Assert(header.cmap_depth==24);
593                 Assert(header.cmap_length<=256);
594                 Assert(palette);
595
596                 // Read the color map data
597                 int i;
598                 for (i = 0; i < header.cmap_length; i++)        {
599                         r = cfread_ubyte(targa_file);
600                         g = cfread_ubyte(targa_file);
601                         b = cfread_ubyte(targa_file);
602
603                         if(palette != NULL){
604                                 palette[i*3+2] = r;
605                                 palette[i*3+1] = g;
606                                 palette[i*3+0] = b;
607                         }
608                 } 
609                 // Fill out with black.
610                 if(palette != NULL){
611                         for (; i < 256; i++)    {
612                                 palette[i*3+2] = 0;
613                                 palette[i*3+1] = 0;
614                                 palette[i*3+0] = 0;
615                         }
616                 }
617         }
618         
619         int bytes_remaining = cfilelength(targa_file)-cftell(targa_file);
620
621         Assert(bytes_remaining>0);
622
623         ubyte *fileptr = (ubyte*)malloc(bytes_remaining);
624         Assert(fileptr);
625         if(fileptr == NULL){
626                 return TARGA_ERROR_READING;
627         }
628
629         ubyte *src_pixels = fileptr;
630
631         cfread(fileptr, bytes_remaining, 1, targa_file);        
632         
633         int rowsize = header.width * bytes_per_pixel;   
634
635         if ( (header.image_type == 1) || (header.image_type == 2) || (header.image_type == 3) ) {
636                 // Uncompressed read
637
638                 for (int i = 0; i < header.height; i++) {
639                         ubyte * pixptr;
640
641                         if ( ULORIGIN ) {
642                                 pixptr = image_data + i * rowsize;
643                         } else {
644                                 pixptr = image_data + ((header.height - i - 1) * rowsize);
645                         }
646                          
647                         targa_read_pixel(header.width, &pixptr, &src_pixels, bytes_per_pixel, dest_size );
648                 }
649
650         } else if (header.image_type == 9 || header.image_type == 10 || header.image_type == 11) {
651
652                 // the following handles RLE'ed targa data. 
653
654                 // targas encoded by the scanline -- loop on the height
655                 for (int i = 0; i < header.height; i++) {
656                         ubyte *pixdata;
657
658                         if (ULORIGIN)   {
659                                 pixdata = image_data + i * rowsize;
660                         } else {
661                                 pixdata = image_data + ((header.height - i - 1) * rowsize);
662                         }
663
664                         src_pixels += targa_uncompress( pixdata, src_pixels, header.width, bytes_per_pixel, dest_size );
665                 }
666
667         }
668
669         free(fileptr);
670         cfclose(targa_file);
671         targa_file = NULL;
672
673         return TARGA_ERROR_NONE;
674 }
675
676 // Write out a Targa format bitmap.  Always writes out a top-up bitmap. 
677 // JAS: DOESN'T WORK WITH 8-BPP PALETTES
678 //
679 // filename: name of the Targa file, .tga extension added if not passed in
680 // data:     raw image data
681 // w:        width of the bitmap in pixels
682 // h:        height of the bitmap in pixels
683 // bpp:      bits per pixel of the bitmap
684 //
685 // returns:  0 if successful, otherwise -1
686 //
687 int targa_write_bitmap(char *real_filename, ubyte *data, ubyte *palette, int w, int h, int bpp)
688 {
689         Assert(bpp == 24);
690         char filename[MAX_FILENAME_LEN];
691         CFILE *f;
692         int bytes_per_pixel = BYTES_PER_PIXEL(bpp);             
693                 
694         // open the file
695         strcpy( filename, real_filename );
696         char *p = strchr( filename, '.' );
697         if ( p ) *p = 0;
698         strcat( filename, ".tga" );
699
700         f = cfopen( filename , "wb" );
701         if ( !f ){
702                 return TARGA_ERROR_READING;
703         }                       
704
705         // Write the TGA header
706         cfwrite_ubyte(0, f);
707         // f.write_ubyte(0);                            //      IDLength
708
709         cfwrite_ubyte(0, f);
710         //f.write_ubyte(0);                             //      ColorMapType
711
712         cfwrite_ubyte(10, f);
713         // f.write_ubyte(10);                   //      image_type: 2 = 24bpp, uncompressed, 10=24bpp rle compressed
714
715         cfwrite_ushort(0, f);
716         // f.write_ushort(0);                   // CMapStart
717
718         cfwrite_ushort(0, f);
719         // f.write_ushort(0);                   //      CMapLength
720
721         cfwrite_ubyte(0, f);
722         // f.write_ubyte(0);                            // CMapDepth
723
724         cfwrite_ushort(0, f);
725         // f.write_ushort(0);                   //      XOffset
726
727         cfwrite_ushort(0, f);
728         // f.write_ushort(0);                   //      YOffset
729
730         cfwrite_ushort((ushort)w, f);
731         // f.write_ushort((ushort)w);   //      Width
732
733         cfwrite_ushort((ushort)h, f);
734         // f.write_ushort((ushort)h);   //      Height
735
736         cfwrite_ubyte(24, f);
737         // f.write_ubyte(24);                   // pixel_depth
738
739         cfwrite_ubyte(0x20, f);
740         // f.write_ubyte(0x20);                         // ImageDesc  ( 0x20 = Origin at upper left )
741
742         ubyte *compressed_data;
743         compressed_data = (ubyte*)malloc(w * h * bytes_per_pixel);
744         Assert(compressed_data);
745         if(compressed_data == NULL){
746                 cfclose(f);
747                 return -1;
748         }
749
750         int compressed_data_len;
751         compressed_data_len = targa_compress((char*)compressed_data, (char*)data, 3, bytes_per_pixel, w * h * bytes_per_pixel);
752         if (compressed_data_len < 0) {
753                 free(compressed_data);
754                 cfclose(f);             
755                 return -1;
756         }
757
758         cfwrite(compressed_data, compressed_data_len, 1, f);
759         cfclose(f);
760         f = NULL;
761
762         return 0;
763 }