• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

src/contrib/libtarga.c

Go to the documentation of this file.
00001 
00002 /**************************************************************************
00003  ** Simplified TARGA library for Intro to Graphics Classes
00004  **
00005  ** This is a simple library for reading and writing image files in
00006  ** the TARGA file format (which is a simple format). 
00007  ** The routines are intentionally designed to be simple for use in
00008  ** into to graphics assignments - a more full-featured targa library
00009  ** also exists for other uses.
00010  **
00011  ** This library was originally written by Alex Mohr who has assigned
00012  ** copyright to Michael Gleicher. The code is made available under an
00013  ** "MIT" Open Source license.
00014  **/
00015 
00040 /*
00041 ** libtarga.c -- routines for reading targa files.
00042 */
00043 
00044 /*
00045   Modified by yu-chi because of initialization of variables at tga_load
00046   09-16-2005
00047 */
00048 
00049 #include <stdio.h>
00050 #include <malloc.h>
00051 
00052 #include "contrib/libtarga.h"
00053 
00054 
00055 
00056 
00057 #define TGA_IMG_NODATA             (0)
00058 #define TGA_IMG_UNC_PALETTED       (1)
00059 #define TGA_IMG_UNC_TRUECOLOR      (2)
00060 #define TGA_IMG_UNC_GRAYSCALE      (3)
00061 #define TGA_IMG_RLE_PALETTED       (9)
00062 #define TGA_IMG_RLE_TRUECOLOR      (10)
00063 #define TGA_IMG_RLE_GRAYSCALE      (11)
00064 
00065 
00066 #define TGA_LOWER_LEFT             (0)
00067 #define TGA_LOWER_RIGHT            (1)
00068 #define TGA_UPPER_LEFT             (2)
00069 #define TGA_UPPER_RIGHT            (3)
00070 
00071 
00072 #define HDR_LENGTH               (18)
00073 #define HDR_IDLEN                (0)
00074 #define HDR_CMAP_TYPE            (1)
00075 #define HDR_IMAGE_TYPE           (2)
00076 #define HDR_CMAP_FIRST           (3)
00077 #define HDR_CMAP_LENGTH          (5)
00078 #define HDR_CMAP_ENTRY_SIZE      (7)
00079 #define HDR_IMG_SPEC_XORIGIN     (8)
00080 #define HDR_IMG_SPEC_YORIGIN     (10)
00081 #define HDR_IMG_SPEC_WIDTH       (12)
00082 #define HDR_IMG_SPEC_HEIGHT      (14)
00083 #define HDR_IMG_SPEC_PIX_DEPTH   (16)
00084 #define HDR_IMG_SPEC_IMG_DESC    (17)
00085 
00086 
00087 
00088 #define TGA_ERR_NONE                    (0)
00089 #define TGA_ERR_BAD_HEADER              (1)
00090 #define TGA_ERR_OPEN_FAILS              (2)
00091 #define TGA_ERR_BAD_FORMAT              (3)
00092 #define TGA_ERR_UNEXPECTED_EOF          (4)
00093 #define TGA_ERR_NODATA_IMAGE            (5)
00094 #define TGA_ERR_COLORMAP_FOR_GRAY       (6)
00095 #define TGA_ERR_BAD_COLORMAP_ENTRY_SIZE (7)
00096 #define TGA_ERR_BAD_COLORMAP            (8)
00097 #define TGA_ERR_READ_FAILS              (9)
00098 #define TGA_ERR_BAD_IMAGE_TYPE          (10)
00099 #define TGA_ERR_BAD_DIMENSIONS          (11)
00100 
00101 
00102 
00103 static uint32 TargaError;
00104 
00105 
00106 static int16 ttohs( int16 val );
00107 static int16 htots( int16 val );
00108 static int32 ttohl( int32 val );
00109 static int32 htotl( int32 val );
00110 
00111 
00112 static uint32 tga_get_pixel( FILE * tga, ubyte bytes_per_pix, 
00113                             ubyte * colormap, ubyte cmap_bytes_entry );
00114 static uint32 tga_convert_color( uint32 pixel, uint32 bpp_in, ubyte alphabits, uint32 format_out );
00115 static void tga_write_pixel_to_mem( ubyte * dat, ubyte img_spec, uint32 number, 
00116                                    uint32 w, uint32 h, uint32 pixel, uint32 format );
00117 
00118 
00119 
00120 /* returns the last error encountered */
00121 int tga_get_last_error() {
00122     return( TargaError );
00123 }
00124 
00125 
00126 /* returns a pointer to the string for an error code */
00127 const char * tga_error_string( int error_code ) {
00128 
00129     switch( error_code ) {
00130     
00131     case TGA_ERR_NONE:
00132         return( "no error" );
00133 
00134     case TGA_ERR_BAD_HEADER:
00135         return( "bad image header" );
00136 
00137     case TGA_ERR_OPEN_FAILS:
00138         return( "cannot open file" );
00139 
00140     case TGA_ERR_BAD_FORMAT:
00141         return( "bad format argument" );
00142 
00143     case TGA_ERR_UNEXPECTED_EOF:
00144         return( "unexpected end-of-file" );
00145 
00146     case TGA_ERR_NODATA_IMAGE:
00147         return( "image contains no data" );
00148 
00149     case TGA_ERR_COLORMAP_FOR_GRAY:
00150         return( "found colormap for a grayscale image" );
00151 
00152     case TGA_ERR_BAD_COLORMAP_ENTRY_SIZE:
00153         return( "unsupported colormap entry size" );
00154 
00155     case TGA_ERR_BAD_COLORMAP:
00156         return( "bad colormap" );
00157 
00158     case TGA_ERR_READ_FAILS:
00159         return( "cannot read from file" );
00160 
00161     case TGA_ERR_BAD_IMAGE_TYPE:
00162         return( "unknown image type" );
00163 
00164     case TGA_ERR_BAD_DIMENSIONS:
00165         return( "image has size 0 width or height (or both)" );
00166 
00167     default:
00168         return( "unknown error" );
00169 
00170     }
00171 
00172     // shut up compiler..
00173     return( NULL );
00174 
00175 }
00176 
00177 
00178 
00179 /* creates a targa image of the desired format */
00180 void * tga_create( int width, int height, unsigned int format ) {
00181 
00182     switch( format ) {
00183         
00184     case TGA_TRUECOLOR_32:
00185         return( (void *)malloc( width * height * 4 ) );
00186         
00187     case TGA_TRUECOLOR_24:
00188         return( (void *)malloc( width * height * 3 ) );
00189         
00190     default:
00191         TargaError = TGA_ERR_BAD_FORMAT;
00192         break;
00193 
00194     }
00195 
00196     return( NULL );
00197 
00198 }
00199 
00200 
00201 
00202 /* loads and converts a targa from disk */
00203 void * tga_load( const char * filename, 
00204                 int * width, int * height, unsigned int format ) {
00205     
00206     ubyte  idlen;               // length of the image_id string below.
00207     ubyte  cmap_type;           // paletted image <=> cmap_type
00208     ubyte  image_type;          // can be any of the IMG_TYPE constants above.
00209     uint16 cmap_first;          // 
00210     uint16 cmap_length;         // how long the colormap is
00211     ubyte  cmap_entry_size;     // how big a palette entry is.
00212     uint16 img_spec_xorig;      // the x origin of the image in the image data.
00213     uint16 img_spec_yorig;      // the y origin of the image in the image data.
00214     uint16 img_spec_width;      // the width of the image.
00215     uint16 img_spec_height;     // the height of the image.
00216     ubyte  img_spec_pix_depth;  // the depth of a pixel in the image.
00217     ubyte  img_spec_img_desc;   // the image descriptor.
00218 
00219     FILE * targafile;
00220 
00221     ubyte * tga_hdr = NULL;
00222 
00223     ubyte * colormap = NULL;
00224 
00225     //***********************************************************************
00226     // Add by Yu-Chi because of variable initialization.
00227     // Add all = 0 to all the following variables
00228     //***********************************************************************
00229 
00230 
00231     ubyte cmap_bytes_entry = 0;
00232     uint32 cmap_bytes = 0;
00233     
00234     uint32 tmp_col = 0;
00235     uint32 tmp_int32 = 0;
00236     ubyte  tmp_byte = 0;
00237 
00238     ubyte alphabits = 0;
00239 
00240     uint32 num_pixels = 0;
00241     
00242     uint32 i = 0;
00243     uint32 j = 0;
00244 
00245     ubyte * image_data = 0;
00246     uint32 img_dat_len = 0;
00247 
00248     ubyte bytes_per_pix = 0;
00249 
00250     ubyte true_bits_per_pixel = 0;
00251 
00252     uint32 bytes_total = 0;
00253 
00254     ubyte packet_header = 0;
00255     ubyte repcount = 0;
00256     
00257 
00258     switch( format ) {
00259 
00260     case TGA_TRUECOLOR_24:
00261     case TGA_TRUECOLOR_32:
00262         break;
00263 
00264     default:
00265         TargaError = TGA_ERR_BAD_FORMAT;
00266         return( NULL );
00267 
00268     }
00269 
00270     
00271     /* open binary image file */
00272     targafile = fopen( filename, "rb" );
00273     if( targafile == NULL ) {
00274         TargaError = TGA_ERR_OPEN_FAILS;
00275         return( NULL );
00276     }
00277 
00278 
00279     /* allocate memory for the header */
00280     tga_hdr = (ubyte *)malloc( HDR_LENGTH );
00281 
00282     /* read the header in. */
00283     if( fread( (void *)tga_hdr, 1, HDR_LENGTH, targafile ) != HDR_LENGTH ) {
00284         free( tga_hdr );
00285         TargaError = TGA_ERR_BAD_HEADER;
00286         return( NULL );
00287     }
00288 
00289     
00290     /* byte order is important here. */
00291     idlen              = (ubyte)tga_hdr[HDR_IDLEN];
00292     
00293     image_type         = (ubyte)tga_hdr[HDR_IMAGE_TYPE];
00294     
00295     cmap_type          = (ubyte)tga_hdr[HDR_CMAP_TYPE];
00296     cmap_first         = ttohs( *(uint16 *)(&tga_hdr[HDR_CMAP_FIRST]) );
00297     cmap_length        = ttohs( *(uint16 *)(&tga_hdr[HDR_CMAP_LENGTH]) );
00298     cmap_entry_size    = (ubyte)tga_hdr[HDR_CMAP_ENTRY_SIZE];
00299 
00300     img_spec_xorig     = ttohs( *(uint16 *)(&tga_hdr[HDR_IMG_SPEC_XORIGIN]) );
00301     img_spec_yorig     = ttohs( *(uint16 *)(&tga_hdr[HDR_IMG_SPEC_YORIGIN]) );
00302     img_spec_width     = ttohs( *(uint16 *)(&tga_hdr[HDR_IMG_SPEC_WIDTH]) );
00303     img_spec_height    = ttohs( *(uint16 *)(&tga_hdr[HDR_IMG_SPEC_HEIGHT]) );
00304     img_spec_pix_depth = (ubyte)tga_hdr[HDR_IMG_SPEC_PIX_DEPTH];
00305     img_spec_img_desc  = (ubyte)tga_hdr[HDR_IMG_SPEC_IMG_DESC];
00306 
00307     free( tga_hdr );
00308 
00309 
00310     num_pixels = img_spec_width * img_spec_height;
00311 
00312     if( num_pixels == 0 ) {
00313         TargaError = TGA_ERR_BAD_DIMENSIONS;
00314         return( NULL );
00315     }
00316 
00317     
00318     alphabits = img_spec_img_desc & 0x0F;
00319 
00320     
00321     /* seek past the image id, if there is one */
00322     if( idlen ) {
00323         if( fseek( targafile, idlen, SEEK_CUR ) ) {
00324             TargaError = TGA_ERR_UNEXPECTED_EOF;
00325             return( NULL );
00326         }
00327     }
00328 
00329 
00330     /* if this is a 'nodata' image, just jump out. */
00331     if( image_type == TGA_IMG_NODATA ) {
00332         TargaError = TGA_ERR_NODATA_IMAGE;
00333         return( NULL );
00334     }
00335 
00336 
00337     /* now we're starting to get into the meat of the matter. */
00338     
00339     
00340     /* deal with the colormap, if there is one. */
00341     if( cmap_type ) {
00342 
00343         switch( image_type ) {
00344             
00345         case TGA_IMG_UNC_PALETTED:
00346         case TGA_IMG_RLE_PALETTED:
00347             break;
00348             
00349         case TGA_IMG_UNC_TRUECOLOR:
00350         case TGA_IMG_RLE_TRUECOLOR:
00351             // this should really be an error, but some really old
00352             // crusty targas might actually be like this (created by TrueVision, no less!)
00353             // so, we'll hack our way through it.
00354             break;
00355             
00356         case TGA_IMG_UNC_GRAYSCALE:
00357         case TGA_IMG_RLE_GRAYSCALE:
00358             TargaError = TGA_ERR_COLORMAP_FOR_GRAY;
00359             return( NULL );
00360         }
00361         
00362         /* ensure colormap entry size is something we support */
00363         if( !(cmap_entry_size == 15 || 
00364             cmap_entry_size == 16 ||
00365             cmap_entry_size == 24 ||
00366             cmap_entry_size == 32) ) {
00367             TargaError = TGA_ERR_BAD_COLORMAP_ENTRY_SIZE;
00368             return( NULL );
00369         }
00370         
00371         
00372         /* allocate memory for a colormap */
00373         if( cmap_entry_size & 0x07 ) {
00374             cmap_bytes_entry = (((8 - (cmap_entry_size & 0x07)) + cmap_entry_size) >> 3);
00375         } else {
00376             cmap_bytes_entry = (cmap_entry_size >> 3);
00377         }
00378         
00379         cmap_bytes = cmap_bytes_entry * cmap_length;
00380         colormap = (ubyte *)malloc( cmap_bytes );
00381         
00382         
00383         for( i = 0; i < cmap_length; i++ ) {
00384             
00385             /* seek ahead to first entry used */
00386             if( cmap_first != 0 ) {
00387                 fseek( targafile, cmap_first * cmap_bytes_entry, SEEK_CUR );
00388             }
00389             
00390             tmp_int32 = 0;
00391             for( j = 0; j < cmap_bytes_entry; j++ ) {
00392                 if( !fread( &tmp_byte, 1, 1, targafile ) ) {
00393                     free( colormap );
00394                     TargaError = TGA_ERR_BAD_COLORMAP;
00395                     return( NULL );
00396                 }
00397                 tmp_int32 += tmp_byte << (j * 8);
00398             }
00399 
00400             // byte order correct.
00401             tmp_int32 = ttohl( tmp_int32 );
00402 
00403             for( j = 0; j < cmap_bytes_entry; j++ ) {
00404                 colormap[i * cmap_bytes_entry + j] = (tmp_int32 >> (8 * j)) & 0xFF;
00405             }
00406             
00407         }
00408 
00409     }
00410 
00411 
00412     // compute number of bytes in an image data unit (either index or BGR triple)
00413     if( img_spec_pix_depth & 0x07 ) {
00414         bytes_per_pix = (((8 - (img_spec_pix_depth & 0x07)) + img_spec_pix_depth) >> 3);
00415     } else {
00416         bytes_per_pix = (img_spec_pix_depth >> 3);
00417     }
00418 
00419 
00420     /* assume that there's one byte per pixel */
00421     if( bytes_per_pix == 0 ) {
00422         bytes_per_pix = 1;
00423     }
00424 
00425 
00426     /* compute how many bytes of storage we need for the image */
00427     bytes_total = img_spec_width * img_spec_height * format;
00428 
00429     image_data = (ubyte *)malloc( bytes_total );
00430 
00431     img_dat_len = img_spec_width * img_spec_height * bytes_per_pix;
00432 
00433     // compute the true number of bits per pixel
00434     true_bits_per_pixel = cmap_type ? cmap_entry_size : img_spec_pix_depth;
00435 
00436     switch( image_type ) {
00437 
00438     case TGA_IMG_UNC_TRUECOLOR:
00439     case TGA_IMG_UNC_GRAYSCALE:
00440     case TGA_IMG_UNC_PALETTED:
00441 
00442         /* FIXME: support grayscale */
00443 
00444         for( i = 0; i < num_pixels; i++ ) {
00445 
00446             // get the color value.
00447             tmp_col = tga_get_pixel( targafile, bytes_per_pix, colormap, cmap_bytes_entry );
00448             tmp_col = tga_convert_color( tmp_col, true_bits_per_pixel, alphabits, format );
00449             
00450             // now write the data out.
00451             tga_write_pixel_to_mem( image_data, img_spec_img_desc, 
00452                 i, img_spec_width, img_spec_height, tmp_col, format );
00453 
00454         }
00455     
00456         break;
00457 
00458 
00459     case TGA_IMG_RLE_TRUECOLOR:
00460     case TGA_IMG_RLE_GRAYSCALE:
00461     case TGA_IMG_RLE_PALETTED:
00462 
00463         // FIXME: handle grayscale..
00464 
00465         for( i = 0; i < num_pixels; ) {
00466 
00467             /* a bit of work to do to read the data.. */
00468             if( fread( &packet_header, 1, 1, targafile ) < 1 ) {
00469                 // well, just let them fill the rest with null pixels then...
00470                 packet_header = 1;
00471             }
00472 
00473             if( packet_header & 0x80 ) {
00474                 /* run length packet */
00475 
00476                 tmp_col = tga_get_pixel( targafile, bytes_per_pix, colormap, cmap_bytes_entry );
00477                 tmp_col = tga_convert_color( tmp_col, true_bits_per_pixel, alphabits, format );
00478                 
00479                 repcount = (packet_header & 0x7F) + 1;
00480                 
00481                 /* write all the data out */
00482                 for( j = 0; j < repcount; j++ ) {
00483                     tga_write_pixel_to_mem( image_data, img_spec_img_desc, 
00484                         i + j, img_spec_width, img_spec_height, tmp_col, format );
00485                 }
00486 
00487                 i += repcount;
00488 
00489             } else {
00490                 /* raw packet */
00491                 /* get pixel from file */
00492                 
00493                 repcount = (packet_header & 0x7F) + 1;
00494                 
00495                 for( j = 0; j < repcount; j++ ) {
00496                     
00497                     tmp_col = tga_get_pixel( targafile, bytes_per_pix, colormap, cmap_bytes_entry );
00498                     tmp_col = tga_convert_color( tmp_col, true_bits_per_pixel, alphabits, format );
00499                     
00500                     tga_write_pixel_to_mem( image_data, img_spec_img_desc, 
00501                         i + j, img_spec_width, img_spec_height, tmp_col, format );
00502 
00503                 }
00504 
00505                 i += repcount;
00506 
00507             }
00508 
00509         }
00510 
00511         break;
00512     
00513 
00514     default:
00515 
00516         TargaError = TGA_ERR_BAD_IMAGE_TYPE;
00517         return( NULL );
00518 
00519     }
00520 
00521     fclose( targafile );
00522 
00523     *width  = img_spec_width;
00524     *height = img_spec_height;
00525 
00526     return( (void *)image_data );
00527 
00528 }
00529 
00530 
00531 
00532 
00533 
00534 int tga_write_raw( const char * file, int width, int height, unsigned char * dat, unsigned int format ) {
00535 
00536     FILE * tga;
00537 
00538     uint32 i, j;
00539 
00540     uint32 size = width * height;
00541 
00542     float red, green, blue, alpha;
00543 
00544     char id[] = "written with libtarga";
00545     ubyte idlen = 21;
00546     ubyte zeroes[5] = { 0, 0, 0, 0, 0 };
00547     uint32 pixbuf;
00548     ubyte one = 1;
00549     ubyte cmap_type = 0;
00550     ubyte img_type  = 2;  // 2 - uncompressed truecolor  10 - RLE truecolor
00551     uint16 xorigin  = 0;
00552     uint16 yorigin  = 0;
00553     ubyte  pixdepth = format * 8;  // bpp
00554     ubyte img_desc;
00555     
00556     
00557     switch( format ) {
00558 
00559     case TGA_TRUECOLOR_24:
00560         img_desc = 0;
00561         break;
00562 
00563     case TGA_TRUECOLOR_32:
00564         img_desc = 8;
00565         break;
00566 
00567     default:
00568         TargaError = TGA_ERR_BAD_FORMAT;
00569         return( 0 );
00570         break;
00571 
00572     }
00573 
00574     tga = fopen( file, "wb" );
00575 
00576     if( tga == NULL ) {
00577         TargaError = TGA_ERR_OPEN_FAILS;
00578         return( 0 );
00579     }
00580 
00581     // write id length
00582     fwrite( &idlen, 1, 1, tga );
00583 
00584     // write colormap type
00585     fwrite( &cmap_type, 1, 1, tga );
00586 
00587     // write image type
00588     fwrite( &img_type, 1, 1, tga );
00589 
00590     // write cmap spec.
00591     fwrite( &zeroes, 5, 1, tga );
00592 
00593     // write image spec.
00594     fwrite( &xorigin, 2, 1, tga );
00595     fwrite( &yorigin, 2, 1, tga );
00596     fwrite( &width, 2, 1, tga );
00597     fwrite( &height, 2, 1, tga );
00598     fwrite( &pixdepth, 1, 1, tga );
00599     fwrite( &img_desc, 1, 1, tga );
00600 
00601 
00602     // write image id.
00603     fwrite( &id, idlen, 1, tga );
00604 
00605     // color correction -- data is in RGB, need BGR.
00606     for( i = 0; i < size; i++ ) {
00607 
00608         pixbuf = 0;
00609         for( j = 0; j < format; j++ ) {
00610             pixbuf += dat[i*format+j] << (8 * j);
00611         }
00612 
00613         switch( format ) {
00614 
00615         case TGA_TRUECOLOR_24:
00616 
00617             pixbuf = ((pixbuf & 0xFF) << 16) + 
00618                      (pixbuf & 0xFF00) + 
00619                      ((pixbuf & 0xFF0000) >> 16);
00620 
00621             pixbuf = htotl( pixbuf );
00622             
00623             fwrite( &pixbuf, 3, 1, tga );
00624 
00625             break;
00626 
00627         case TGA_TRUECOLOR_32:
00628 
00629             /* need to un-premultiply alpha.. */
00630 
00631             red     = (pixbuf & 0xFF) / 255.0f;
00632             green   = ((pixbuf & 0xFF00) >> 8) / 255.0f;
00633             blue    = ((pixbuf & 0xFF0000) >> 16) / 255.0f;
00634             alpha   = ((pixbuf & 0xFF000000) >> 24) / 255.0f;
00635 
00636             if( alpha > 0.0001 ) {
00637                 red /= alpha;
00638                 green /= alpha;
00639                 blue /= alpha;
00640             }
00641 
00642             /* clamp to 1.0f */
00643 
00644             red = red > 1.0f ? 255.0f : red * 255.0f;
00645             green = green > 1.0f ? 255.0f : green * 255.0f;
00646             blue = blue > 1.0f ? 255.0f : blue * 255.0f;
00647             alpha = alpha > 1.0f ? 255.0f : alpha * 255.0f;
00648 
00649             pixbuf = (ubyte)blue + (((ubyte)green) << 8) + 
00650                 (((ubyte)red) << 16) + (((ubyte)alpha) << 24);
00651                 
00652             pixbuf = htotl( pixbuf );
00653            
00654             fwrite( &pixbuf, 4, 1, tga );
00655 
00656             break;
00657 
00658         }
00659 
00660     }
00661 
00662     fclose( tga );
00663 
00664     return( 1 );
00665 
00666 }
00667 
00668 
00669 
00670 
00671 
00672 int tga_write_rle( const char * file, int width, int height, unsigned char * dat, unsigned int format ) {
00673 
00674     FILE * tga;
00675 
00676     uint32 i, j;
00677     uint32 oc, nc;
00678 
00679     enum RLE_STATE { INIT, NONE, RLP, RAWP };
00680 
00681     int state = INIT;
00682 
00683     uint32 size = width * height;
00684 
00685     uint16 shortwidth = (uint16)width;
00686     uint16 shortheight = (uint16)height;
00687 
00688     ubyte repcount;
00689 
00690     float red, green, blue, alpha;
00691 
00692     int idx, row, column;
00693 
00694     // have to buffer a whole line for raw packets.
00695     unsigned char * rawbuf = (unsigned char *)malloc( width * format );  
00696 
00697     char id[] = "written with libtarga";
00698     ubyte idlen = 21;
00699     ubyte zeroes[5] = { 0, 0, 0, 0, 0 };
00700     uint32 pixbuf;
00701     ubyte one = 1;
00702     ubyte cmap_type = 0;
00703     ubyte img_type  = 10;  // 2 - uncompressed truecolor  10 - RLE truecolor
00704     uint16 xorigin  = 0;
00705     uint16 yorigin  = 0;
00706     ubyte  pixdepth = format * 8;  // bpp
00707     ubyte img_desc  = format == TGA_TRUECOLOR_32 ? 8 : 0;
00708   
00709 
00710     switch( format ) {
00711     case TGA_TRUECOLOR_24:
00712     case TGA_TRUECOLOR_32:
00713         break;
00714 
00715     default:
00716         TargaError = TGA_ERR_BAD_FORMAT;
00717         return( 0 );
00718     }
00719 
00720 
00721     tga = fopen( file, "wb" );
00722 
00723     if( tga == NULL ) {
00724         TargaError = TGA_ERR_OPEN_FAILS;
00725         return( 0 );
00726     }
00727 
00728     // write id length
00729     fwrite( &idlen, 1, 1, tga );
00730 
00731     // write colormap type
00732     fwrite( &cmap_type, 1, 1, tga );
00733 
00734     // write image type
00735     fwrite( &img_type, 1, 1, tga );
00736 
00737     // write cmap spec.
00738     fwrite( &zeroes, 5, 1, tga );
00739 
00740     // write image spec.
00741     fwrite( &xorigin, 2, 1, tga );
00742     fwrite( &yorigin, 2, 1, tga );
00743     fwrite( &shortwidth, 2, 1, tga );
00744     fwrite( &shortheight, 2, 1, tga );
00745     fwrite( &pixdepth, 1, 1, tga );
00746     fwrite( &img_desc, 1, 1, tga );
00747 
00748 
00749     // write image id.
00750     fwrite( &id, idlen, 1, tga );
00751 
00752     // initial color values -- just to shut up the compiler.
00753     nc = 0;
00754 
00755     // color correction -- data is in RGB, need BGR.
00756     // also run-length-encoding.
00757     for( i = 0; i < size; i++ ) {
00758 
00759         idx = i * format;
00760 
00761         row = i / width;
00762         column = i % width;
00763 
00764         //printf( "row: %d, col: %d\n", row, column );
00765         pixbuf = 0;
00766         for( j = 0; j < format; j++ ) {
00767             pixbuf += dat[idx+j] << (8 * j);
00768         }
00769 
00770         switch( format ) {
00771 
00772         case TGA_TRUECOLOR_24:
00773 
00774             pixbuf = ((pixbuf & 0xFF) << 16) + 
00775                      (pixbuf & 0xFF00) + 
00776                      ((pixbuf & 0xFF0000) >> 16);
00777 
00778             pixbuf = htotl( pixbuf );
00779             break;
00780 
00781         case TGA_TRUECOLOR_32:
00782 
00783             /* need to un-premultiply alpha.. */
00784 
00785             red     = (pixbuf & 0xFF) / 255.0f;
00786             green   = ((pixbuf & 0xFF00) >> 8) / 255.0f;
00787             blue    = ((pixbuf & 0xFF0000) >> 16) / 255.0f;
00788             alpha   = ((pixbuf & 0xFF000000) >> 24) / 255.0f;
00789 
00790             if( alpha > 0.0001 ) {
00791                 red /= alpha;
00792                 green /= alpha;
00793                 blue /= alpha;
00794             }
00795 
00796             /* clamp to 1.0f */
00797 
00798             red = red > 1.0f ? 255.0f : red * 255.0f;
00799             green = green > 1.0f ? 255.0f : green * 255.0f;
00800             blue = blue > 1.0f ? 255.0f : blue * 255.0f;
00801             alpha = alpha > 1.0f ? 255.0f : alpha * 255.0f;
00802 
00803             pixbuf = (ubyte)blue + (((ubyte)green) << 8) + 
00804                 (((ubyte)red) << 16) + (((ubyte)alpha) << 24);
00805                 
00806             pixbuf = htotl( pixbuf );
00807             break;
00808 
00809         }
00810 
00811 
00812         oc = nc;
00813 
00814         nc = pixbuf;
00815 
00816 
00817         switch( state ) {
00818 
00819         case INIT:
00820             // this is just used to make sure we have 2 pixel values to consider.
00821             state = NONE;
00822             break;
00823 
00824 
00825         case NONE:
00826 
00827             if( column == 0 ) {
00828                 // write a 1 pixel raw packet for the old pixel, then go thru again.
00829                 repcount = 0;
00830                 fwrite( &repcount, 1, 1, tga );
00831 #ifdef WORDS_BIGENDIAN
00832                 fwrite( (&oc)+4, format, 1, tga );  // byte order..
00833 #else
00834                 fwrite( &oc, format, 1, tga );
00835 #endif
00836                 state = NONE;
00837                 break;
00838             }
00839 
00840             if( nc == oc ) {
00841                 repcount = 0;
00842                 state = RLP;
00843             } else {
00844                 repcount = 0;
00845                 state = RAWP;
00846                 for( j = 0; j < format; j++ ) {
00847 #ifdef WORDS_BIGENDIAN
00848                     rawbuf[(repcount * format) + j] = (ubyte)(*((&oc)+format-j-1));
00849 #else
00850                     rawbuf[(repcount * format) + j] = *(((ubyte *)(&oc)) + j);
00851 #endif
00852                 }
00853             }
00854             break;
00855 
00856 
00857         case RLP:
00858             repcount++;
00859 
00860             if( column == 0 ) {
00861                 // finish off rlp.
00862                 repcount |= 0x80;
00863                 fwrite( &repcount, 1, 1, tga );
00864 #ifdef WORDS_BIGENDIAN
00865                 fwrite( (&oc)+4, format, 1, tga );  // byte order..
00866 #else
00867                 fwrite( &oc, format, 1, tga );
00868 #endif
00869                 state = NONE;
00870                 break;
00871             }
00872 
00873             if( repcount == 127 ) {
00874                 // finish off rlp.
00875                 repcount |= 0x80;
00876                 fwrite( &repcount, 1, 1, tga );
00877 #ifdef WORDS_BIGENDIAN
00878                 fwrite( (&oc)+4, format, 1, tga );  // byte order..
00879 #else
00880                 fwrite( &oc, format, 1, tga );
00881 #endif
00882                 state = NONE;
00883                 break;
00884             }
00885 
00886             if( nc != oc ) {
00887                 // finish off rlp
00888                 repcount |= 0x80;
00889                 fwrite( &repcount, 1, 1, tga );
00890 #ifdef WORDS_BIGENDIAN
00891                 fwrite( (&oc)+4, format, 1, tga );  // byte order..
00892 #else
00893                 fwrite( &oc, format, 1, tga );
00894 #endif
00895                 state = NONE;
00896             }
00897             break;
00898 
00899 
00900         case RAWP:
00901             repcount++;
00902 
00903             if( column == 0 ) {
00904                 // finish off rawp.
00905                 for( j = 0; j < format; j++ ) {
00906 #ifdef WORDS_BIGENDIAN
00907                     rawbuf[(repcount * format) + j] = (ubyte)(*((&oc)+format-j-1));
00908 #else
00909                     rawbuf[(repcount * format) + j] = *(((ubyte *)(&oc)) + j);
00910 #endif
00911                 }
00912                 fwrite( &repcount, 1, 1, tga );
00913                 fwrite( rawbuf, (repcount + 1) * format, 1, tga );
00914                 state = NONE;
00915                 break;
00916             }
00917 
00918             if( repcount == 127 ) {
00919                 // finish off rawp.
00920                 for( j = 0; j < format; j++ ) {
00921 #ifdef WORDS_BIGENDIAN
00922                     rawbuf[(repcount * format) + j] = (ubyte)(*((&oc)+format-j-1));
00923 #else
00924                     rawbuf[(repcount * format) + j] = *(((ubyte *)(&oc)) + j);
00925 #endif
00926                 }
00927                 fwrite( &repcount, 1, 1, tga );
00928                 fwrite( rawbuf, (repcount + 1) * format, 1, tga );
00929                 state = NONE;
00930                 break;
00931             }
00932 
00933             if( nc == oc ) {
00934                 // finish off rawp
00935                 repcount--;
00936                 fwrite( &repcount, 1, 1, tga );
00937                 fwrite( rawbuf, (repcount + 1) * format, 1, tga );
00938                 
00939                 // start new rlp
00940                 repcount = 0;
00941                 state = RLP;
00942                 break;
00943             }
00944 
00945             // continue making rawp
00946             for( j = 0; j < format; j++ ) {
00947 #ifdef WORDS_BIGENDIAN
00948                 rawbuf[(repcount * format) + j] = (ubyte)(*((&oc)+format-j-1));
00949 #else
00950                 rawbuf[(repcount * format) + j] = *(((ubyte *)(&oc)) + j);
00951 #endif
00952             }
00953 
00954             break;
00955 
00956         }
00957        
00958 
00959     }
00960 
00961 
00962     // clean up state.
00963 
00964     switch( state ) {
00965 
00966     case INIT:
00967         break;
00968 
00969     case NONE:
00970         // write the last 2 pixels in a raw packet.
00971         fwrite( &one, 1, 1, tga );
00972 #ifdef WORDS_BIGENDIAN
00973                 fwrite( (&oc)+4, format, 1, tga );  // byte order..
00974 #else
00975                 fwrite( &oc, format, 1, tga );
00976 #endif
00977 #ifdef WORDS_BIGENDIAN
00978                 fwrite( (&nc)+4, format, 1, tga );  // byte order..
00979 #else
00980                 fwrite( &nc, format, 1, tga );
00981 #endif
00982         break;
00983 
00984     case RLP:
00985         repcount++;
00986         repcount |= 0x80;
00987         fwrite( &repcount, 1, 1, tga );
00988 #ifdef WORDS_BIGENDIAN
00989                 fwrite( (&oc)+4, format, 1, tga );  // byte order..
00990 #else
00991                 fwrite( &oc, format, 1, tga );
00992 #endif
00993         break;
00994 
00995     case RAWP:
00996         repcount++;
00997         for( j = 0; j < format; j++ ) {
00998 #ifdef WORDS_BIGENDIAN
00999             rawbuf[(repcount * format) + j] = (ubyte)(*((&oc)+format-j-1));
01000 #else
01001             rawbuf[(repcount * format) + j] = *(((ubyte *)(&oc)) + j);
01002 #endif
01003         }
01004         fwrite( &repcount, 1, 1, tga );
01005         fwrite( rawbuf, (repcount + 1) * 3, 1, tga );
01006         break;
01007 
01008     }
01009 
01010 
01011     // close the file.
01012     fclose( tga );
01013 
01014     free( rawbuf );
01015 
01016     return( 1 );
01017 
01018 }
01019 
01020 
01021 
01022 
01023 
01024 
01025 /*************************************************************************************************/
01026 
01027 
01028 
01029 
01030 
01031 
01032 
01033 static void tga_write_pixel_to_mem( ubyte * dat, ubyte img_spec, uint32 number, 
01034                                    uint32 w, uint32 h, uint32 pixel, uint32 format ) {
01035 
01036     // write the pixel to the data regarding how the
01037     // header says the data is ordered.
01038 
01039     uint32 j;
01040     uint32 x, y;
01041     uint32 addy;
01042 
01043     switch( (img_spec & 0x30) >> 4 ) {
01044 
01045     case TGA_LOWER_RIGHT:
01046         x = w - 1 - (number % w);
01047         y = number / h;
01048         break;
01049 
01050     case TGA_UPPER_LEFT:
01051         x = number % w;
01052         y = h - 1 - (number / w);
01053         break;
01054 
01055     case TGA_UPPER_RIGHT:
01056         x = w - 1 - (number % w);
01057         y = h - 1 - (number / w);
01058         break;
01059 
01060     case TGA_LOWER_LEFT:
01061     default:
01062         x = number % w;
01063         y = number / w;
01064         break;
01065 
01066     }
01067 
01068     addy = (y * w + x) * format;
01069     for( j = 0; j < format; j++ ) {
01070         dat[addy + j] = (ubyte)((pixel >> (j * 8)) & 0xFF);
01071     }
01072     
01073 }
01074 
01075 
01076 
01077 
01078 
01079 static uint32 tga_get_pixel( FILE * tga, ubyte bytes_per_pix, 
01080                             ubyte * colormap, ubyte cmap_bytes_entry ) {
01081     
01082     /* get the image data value out */
01083 
01084     uint32 tmp_col;
01085     uint32 tmp_int32;
01086     ubyte tmp_byte;
01087 
01088     uint32 j;
01089 
01090     tmp_int32 = 0;
01091     for( j = 0; j < bytes_per_pix; j++ ) {
01092         if( fread( &tmp_byte, 1, 1, tga ) < 1 ) {
01093             tmp_int32 = 0;
01094         } else {
01095             tmp_int32 += tmp_byte << (j * 8);
01096         }
01097     }
01098     
01099     /* byte-order correct the thing */
01100     switch( bytes_per_pix ) {
01101         
01102     case 2:
01103         tmp_int32 = ttohs( (uint16)tmp_int32 );
01104         break;
01105         
01106     case 3: /* intentional fall-thru */
01107     case 4:
01108         tmp_int32 = ttohl( tmp_int32 );
01109         break;
01110         
01111     }
01112     
01113     if( colormap != NULL ) {
01114         /* need to look up value to get real color */
01115         tmp_col = 0;
01116         for( j = 0; j < cmap_bytes_entry; j++ ) {
01117             tmp_col += colormap[cmap_bytes_entry * tmp_int32 + j] << (8 * j);
01118         }
01119     } else {
01120         tmp_col = tmp_int32;
01121     }
01122     
01123     return( tmp_col );
01124     
01125 }
01126 
01127 
01128 
01129 
01130 
01131 static uint32 tga_convert_color( uint32 pixel, uint32 bpp_in, ubyte alphabits, uint32 format_out ) {
01132     
01133     // this is not only responsible for converting from different depths
01134     // to other depths, it also switches BGR to RGB.
01135 
01136     // this thing will also premultiply alpha, on a pixel by pixel basis.
01137 
01138     ubyte r, g, b, a;
01139 
01140     switch( bpp_in ) {
01141         
01142     case 32:
01143         if( alphabits == 0 ) {
01144             goto is_24_bit_in_disguise;
01145         }
01146         // 32-bit to 32-bit -- nop.
01147         break;
01148         
01149     case 24:
01150 is_24_bit_in_disguise:
01151         // 24-bit to 32-bit; (only force alpha to full)
01152         pixel |= 0xFF000000;
01153         break;
01154 
01155     case 15:
01156 is_15_bit_in_disguise:
01157         r = (ubyte)(((float)((pixel & 0x7C00) >> 10)) * 8.2258f);
01158         g = (ubyte)(((float)((pixel & 0x03E0) >> 5 )) * 8.2258f);
01159         b = (ubyte)(((float)(pixel & 0x001F)) * 8.2258f);
01160         // 15-bit to 32-bit; (force alpha to full)
01161         pixel = 0xFF000000 + (r << 16) + (g << 8) + b;
01162         break;
01163         
01164     case 16:
01165         if( alphabits == 1 ) {
01166             goto is_15_bit_in_disguise;
01167         }
01168         // 16-bit to 32-bit; (force alpha to full)
01169         r = (ubyte)(((float)((pixel & 0xF800) >> 11)) * 8.2258f);
01170         g = (ubyte)(((float)((pixel & 0x07E0) >> 5 )) * 4.0476f);
01171         b = (ubyte)(((float)(pixel & 0x001F)) * 8.2258f);
01172         pixel = 0xFF000000 + (r << 16) + (g << 8) + b;
01173         break;
01174        
01175     }
01176     
01177     // convert the 32-bit pixel from BGR to RGB.
01178     pixel = (pixel & 0xFF00FF00) + ((pixel & 0xFF) << 16) + ((pixel & 0xFF0000) >> 16);
01179 
01180     r = pixel & 0x000000FF;
01181     g = (pixel & 0x0000FF00) >> 8;
01182     b = (pixel & 0x00FF0000) >> 16;
01183     a = (pixel & 0xFF000000) >> 24;
01184     
01185     // not premultiplied alpha -- multiply.
01186     r = (ubyte)(((float)r / 255.0f) * ((float)a / 255.0f) * 255.0f);
01187     g = (ubyte)(((float)g / 255.0f) * ((float)a / 255.0f) * 255.0f);
01188     b = (ubyte)(((float)b / 255.0f) * ((float)a / 255.0f) * 255.0f);
01189 
01190     pixel = r + (g << 8) + (b << 16) + (a << 24);
01191 
01192     /* now convert from 32-bit to whatever they want. */
01193     
01194     switch( format_out ) {
01195         
01196     case TGA_TRUECOLOR_32:
01197         // 32 to 32 -- nop.
01198         break;
01199         
01200     case TGA_TRUECOLOR_24:
01201         // 32 to 24 -- discard alpha.
01202         pixel &= 0x00FFFFFF;
01203         break;
01204         
01205     }
01206 
01207     return( pixel );
01208 
01209 }
01210 
01211 
01212 
01213 
01214 static int16 ttohs( int16 val ) {
01215 
01216 #ifdef WORDS_BIGENDIAN
01217     return( ((val & 0xFF) << 8) + (val >> 8) );
01218 #else
01219     return( val );
01220 #endif 
01221 
01222 }
01223 
01224 
01225 static int16 htots( int16 val ) {
01226 
01227 #ifdef WORDS_BIGENDIAN
01228     return( ((val & 0xFF) << 8) + (val >> 8) );
01229 #else
01230     return( val );
01231 #endif
01232 
01233 }
01234 
01235 
01236 static int32 ttohl( int32 val ) {
01237 
01238 #ifdef WORDS_BIGENDIAN
01239     return( ((val & 0x000000FF) << 24) +
01240             ((val & 0x0000FF00) << 8)  +
01241             ((val & 0x00FF0000) >> 8)  +
01242             ((val & 0xFF000000) >> 24) );
01243 #else
01244     return( val );
01245 #endif 
01246 
01247 }
01248 
01249 
01250 static int32 htotl( int32 val ) {
01251 
01252 #ifdef WORDS_BIGENDIAN
01253     return( ((val & 0x000000FF) << 24) +
01254             ((val & 0x0000FF00) << 8)  +
01255             ((val & 0x00FF0000) >> 8)  +
01256             ((val & 0xFF000000) >> 24) );
01257 #else
01258     return( val );
01259 #endif 
01260 
01261 }

Generated on Wed Sep 8 2010 01:36:51 for DGV by  doxygen 1.7.1