home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Copyright (c) 1989, 1990
- ** Truevision, Inc.
- ** All Rights Reserverd
- **
- ** TGAEDIT reads the contents of a Truevision TGA(tm) File and provides
- ** the ability to edit various fields from the console. It will also
- ** convert an original TGA file to the new extended TGA file format.
- **
- ** USAGE:
- ** tgaedit [options] [file1] [file2] ...
- **
- ** If no filenames are provided, the program will prompt for a file
- ** name. If no extension is provided with a filename, the program
- ** will search for the file with ".tga", ".vst", ".icb", ".vda", or
- ** ".win" extension. Options are specified by a leading '-'.
- **
- ** Recognized options are:
- **
- ** -noprompt converts old TGA to new TGA without prompting for data
- ** -nostamp omits creation of postage stamp
- ** -all enables editing of all fields of TGA file, the
- ** default only processes non-critical fields.
- ** -noextend force output file to be old TGA format
- ** -nodev disables copying of developer area
- ** -nocolor disables copying of color correction table
- ** -noscan disables copying of scan line offset table
- ** -version report version number of program
- */
-
- #include <conio.h>
- #include <graph.h>
- #include <io.h>
- #include <malloc.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include "tga.h"
-
- /*
- ** Define byte counts associated with extension areas for various
- ** versions of the TGA specification.
- */
- #define EXT_SIZE_20 495 /* verison 2.0 extension size */
-
- #define WARN 1 /* provides warning message during edit */
- #define NOWARN 0
-
- #define CBUFSIZE 2048 /* size of copy buffer */
- #define RLEBUFSIZ 512 /* size of largest possible RLE packet */
-
-
- extern void main( int, char ** );
- extern int CountDiffPixels( char *, int, int );
- extern long CountRLEData( FILE *, unsigned int, unsigned int, int );
- extern int CountSamePixels( char *, int, int );
- extern int CreatePostageStamp( FILE *, TGAFile *, TGAFile * );
- extern int DisplayImageData( unsigned char *, int, int );
- extern int EditHexNumber( char *, long int, unsigned long int *, long int,
- long int, int );
- extern int EditDecimalNumber( char *, long int, long int *, long int,
- long int, int );
- extern int EditString( char *, int, char *, int );
- extern int EditTGAFields( TGAFile * );
- extern UINT32 GetPixel( unsigned char *, int );
- extern int OutputTGAFile( FILE *, FILE *, TGAFile *, TGAFile *, int,
- struct stat * );
- extern int ParseArgs( int, char ** );
- extern void PrintColorTable( TGAFile * );
- extern void PrintExtendedTGA( TGAFile * );
- extern void PrintImageType( int );
- extern void PrintMonth( UINT16 );
- extern void PrintScanLineTable( TGAFile * );
- extern void PrintTGAInfo( TGAFile * );
- extern UINT8 ReadByte( FILE * );
- extern void ReadCharField( FILE *, char *, int );
- extern int ReadColorTable( FILE *, TGAFile * );
- extern int ReadDeveloperDirectory( FILE *, TGAFile * );
- extern int ReadExtendedTGA( FILE *, TGAFile * );
- extern UINT32 ReadLong( FILE * );
- extern int ReadRLERow( unsigned char *, int, int, FILE * );
- extern int ReadScanLineTable( FILE *, TGAFile * );
- extern UINT16 ReadShort( FILE * );
- extern int RLEncodeRow( char *, char *, int, int );
- extern char *SkipBlank( char * );
- extern int WriteByte( UINT8, FILE * );
- extern int WriteColorTable( FILE *, TGAFile * );
- extern int WriteLong( UINT32, FILE * );
- extern int WriteShort( UINT16, FILE * );
- extern int WriteStr( char *, int, FILE * );
-
-
- /*
- ** String data for performing month conversions
- */
- char *monthStr[] =
- {
- "January",
- "February",
- "March",
- "April",
- "May",
- "June",
- "July",
- "August",
- "September",
- "October",
- "November",
- "December"
- };
-
- /*
- ** String data for interpretting image orientation specification
- */
- char *orientStr[] =
- {
- "Bottom Left",
- "Bottom Right",
- "Top Left",
- "Top Right"
- };
-
- /*
- ** String data for interpretting interleave flag defined with VDA
- ** This field is now obsolete and should typically be set to zero.
- */
- char *interleaveStr[] =
- {
- " Two Way (Even-Odd) Interleave (e.g., IBM Graphics Card Adapter), Obsolete",
- " Four Way Interleave (e.g., AT&T 6300 High Resolution), Obsolete",
- };
-
- /*
- ** Filename extensions used during file search
- */
- char *extNames[] =
- {
- ".tga",
- ".vst",
- ".icb",
- ".vda",
- ".win",
- NULL
- };
-
- TGAFile f; /* control structure of image data */
- TGAFile nf; /* edited version of input structure */
-
- int noPrompt; /* when true, conversion done without prompts */
- int noStamp; /* when true, postage stamp omitted from output */
- int noDev; /* when true, developer area does not get copied */
- int noColor; /* when true, color correction table omitted */
- int noScan; /* when true, scan line table omitted */
- int allFields; /* when true, enables editing of all TGA fields */
- int noExtend; /* when true, output old TGA format */
-
- char rleBuf[RLEBUFSIZ];
-
- char copyBuf[CBUFSIZE];
-
-
- char *versionStr =
- "Truevision(R) TGA(tm) File Edit Utility Version 2.0 - March 24, 1990";
-
- char *warnStr =
- "WARNING: Changing this value may cause loss or corruption of data.";
-
- void
- main( argc, argv )
- int argc;
- char **argv;
- {
- int fileFound;
- int fileCount;
- int files;
- char *q;
- FILE *fp, *outFile;
- long fsize;
- int xTGA; /* flags extended TGA file */
- int i;
- char fileName[80];
- char outFileName[80];
- struct stat statbuf;
-
- noPrompt = 0; /* default to prompting for changes */
- noStamp = 0; /* default to creating postage stamp */
- noDev = 0; /* default to copying developer area, if present */
- noColor = 0; /* default to copying color correction table */
- noScan = 0; /* default to copying scan line offset table */
- allFields = 0; /* default to non-critical fields */
- noExtend = 0; /* defalut to output new extended TGA format */
-
- /*
- ** The program can be invoked without an argument, in which case
- ** the user will be prompted for the name of the image file to be
- ** examined, or the image file name can be provided as an argument
- ** to the command.
- **
- ** File names provided do not need to include the extension if
- ** the image file extension is one of the standard strings common
- ** to Truevision TGA image file names ( e.g., TGA, WIN, VST, VDA, ICB )
- */
- if ( argc == 1 )
- {
- puts( versionStr );
- printf( "Enter name of file to examine: " );
- gets( fileName );
- if ( strlen( fileName ) == 0 ) exit(0);
- fileCount = 1;
- }
- else
- {
- fileCount = ParseArgs( argc, argv );
- if ( fileCount == 0 ) exit( 0 );
- argv++;
- while ( **argv == '-' ) argv++;
- strcpy( fileName, *argv );
- }
- for ( files = 0; files < fileCount; ++files )
- {
- if ( files != 0 )
- {
- argv++;
- while ( **argv == '-' ) argv++;
- strcpy( fileName, *argv );
- }
- /*
- ** See if we can find the file as specified or with one of the
- ** standard filename extensions...
- */
- fileFound = 0;
- if ( stat( fileName, &statbuf ) == 0 ) fileFound = 1;
- else
- {
- /*
- ** If there is already an extension specified, skip
- ** the search for standard extensions
- */
- q = strchr( fileName, '.' );
- if ( q != NULL )
- {
- q = fileName + strlen( fileName );
- }
- else
- {
- i = 0;
- strcat( fileName, extNames[i] );
- q = strchr( fileName, '.' );
- while ( extNames[i] != NULL )
- {
- strcpy( q, extNames[i] );
- if ( stat( fileName, &statbuf ) == 0 )
- {
- fileFound = 1;
- break;
- }
- ++i;
- }
- }
- }
- if ( fileFound )
- {
- _clearscreen( _GCLEARSCREEN );
- printf( "Editing TGA File: %s\n", fileName );
- fp = fopen( fileName, "rb" );
- /*
- ** It would be nice to be able to read in the entire
- ** structure with one fread, but compiler dependent
- ** structure alignment precludes the simplistic approach.
- ** Instead, fill each field individually, and use routines
- ** that will allow code to execute on various hosts by
- ** recompilation with particular compiler flags.
- **
- ** Start by reading the fields associated with the original
- ** TGA format.
- */
- f.idLength = ReadByte( fp );
- f.mapType = ReadByte( fp );
- f.imageType = ReadByte( fp );
- f.mapOrigin = ReadShort( fp );
- f.mapLength = ReadShort( fp );
- f.mapWidth = ReadByte( fp );
- f.xOrigin = ReadShort( fp );
- f.yOrigin = ReadShort( fp );
- f.imageWidth = ReadShort( fp );
- f.imageHeight = ReadShort( fp );
- f.pixelDepth = ReadByte( fp );
- f.imageDesc = ReadByte( fp );
- memset( f.idString, 0, 256 );
- if ( f.idLength > 0 )
- {
- fread( f.idString, 1, f.idLength, fp );
- }
- /*
- ** Now see if the file is the new (extended) TGA format.
- */
- xTGA = 0;
- if ( !fseek( fp, statbuf.st_size - 26, SEEK_SET ) )
- {
- f.extAreaOffset = ReadLong( fp );
- f.devDirOffset = ReadLong( fp );
- fgets( f.signature, 18, fp );
- if ( strcmp( f.signature, "TRUEVISION-XFILE." ) )
- {
- /*
- ** Reset offset values since this is not a new TGA file
- */
- f.extAreaOffset = 0L;
- f.devDirOffset = 0L;
- }
- else xTGA = 1;
- /*
- ** If the file is an original TGA file, and falls into
- ** one of the uncompressed image types, we can perform
- ** an additional file size check with very little effort.
- */
- if ( f.imageType > 0 && f.imageType < 4 && !xTGA )
- {
- /*
- ** Based on the header info, we should be able to calculate
- ** the input file size.
- */
- fsize = 18; /* size of header in bytes */
- fsize += f.idLength;
- /* expect 8, 15, 16, 24, or 32 bits per map entry */
- fsize += ((f.mapWidth + 7) >> 3) * (long)f.mapLength;
- fsize += ((f.pixelDepth + 7) >> 3) * (long)f.imageWidth *
- f.imageHeight;
- if ( fsize != statbuf.st_size )
- {
- /*
- ** Report the error, but continue to process file.
- */
- puts( "Image File Format Error." );
- printf(" Uncompressed File Size Should Be %ld Bytes\n",
- fsize );
- }
- }
- if ( xTGA && f.extAreaOffset )
- {
- if ( ReadExtendedTGA( fp, &f ) < 0 ) exit(1);
- }
- if ( xTGA && f.devDirOffset )
- {
- if ( ReadDeveloperDirectory( fp, &f ) < 0 ) exit(1);
- }
- if ( !noPrompt )
- {
- printf( "Press ENTER to continue: " );
- gets( outFileName );
- }
- /*
- ** Now that we have gathered all this data from the input
- ** file, ask the user which fields should be changed.
- */
- nf = f;
- if ( noPrompt || EditTGAFields( &nf ) >= 0 )
- {
- if ( !noPrompt ) puts( "(Updating File)" );
- /*
- ** If the changes were successful, write out a new
- ** file with the changed data
- */
- strcpy( outFileName, fileName );
- i = strlen( fileName );
- outFileName[ i - 3 ] = '\0'; /* remove extension */
- strcat( outFileName, "$$$" );
- if ( ( outFile = fopen( outFileName, "wb" ) ) != NULL )
- {
- if ( OutputTGAFile( fp, outFile, &f, &nf, xTGA, &statbuf ) < 0 )
- {
- fclose( outFile );
- unlink( outFileName );
- puts( "Error writing output file. No changes made." );
- }
- else
- {
- fclose( outFile );
- fclose( fp );
- fp = (FILE *)0;
- unlink( fileName );
- rename( outFileName, fileName );
- }
- }
- else
- {
- puts( "Unable to create output file." );
- }
- }
- }
- else
- {
- puts( "Error seeking to end of file for possible extension data." );
- }
- if ( f.scanLineTable ) free( f.scanLineTable );
- if ( f.postStamp ) free( f.postStamp );
- if ( f.colorCorrectTable ) free( f.colorCorrectTable );
- if ( f.devDirs ) free( f.devDirs );
- if ( fp != NULL ) fclose( fp );
- }
- else
- {
- *q = '\0';
- printf("Unable to open image file %s\n", fileName );
- }
- }
- }
-
-
-
- /*
- ** Count pixels in buffer until two identical adjacent ones found
- */
-
- int
- CountDiffPixels( p, bpp, pixCnt )
- char *p;
- int bpp;
- int pixCnt;
- {
- unsigned long pixel;
- unsigned long nextPixel;
- int n;
-
- n = 0;
- if ( pixCnt == 1 ) return( pixCnt );
- pixel = GetPixel( p, bpp );
- while ( pixCnt > 1 )
- {
- p += bpp;
- nextPixel = GetPixel( p, bpp );
- if ( nextPixel == pixel ) break;
- pixel = nextPixel;
- ++n;
- --pixCnt;
- }
- if ( nextPixel == pixel ) return( n );
- return( n + 1 );
- }
-
-
-
- long
- CountRLEData( fp, x, y, bytesPerPixel )
- FILE *fp;
- unsigned int x;
- unsigned int y;
- int bytesPerPixel;
- {
- long n;
- long pixelCount;
- long totalPixels;
- unsigned int value;
-
- n = 0L;
- pixelCount = 0L;
- totalPixels = (long)x * (long)y;
-
- while ( pixelCount < totalPixels )
- {
- value = (unsigned int)ReadByte( fp );
- n++;
- if ( value & 0x80 )
- {
- n += bytesPerPixel;
- pixelCount += (value & 0x7f) + 1;
- if ( fread( copyBuf, 1, bytesPerPixel, fp ) != bytesPerPixel )
- {
- puts( "Error counting RLE data." );
- return( 0L );
- }
- }
- else
- {
- value++;
- n += value * bytesPerPixel;
- pixelCount += value;
- if ( fread( copyBuf, bytesPerPixel, value, fp ) != value )
- {
- puts( "Error counting raw data." );
- return( 0L );
- }
- }
- }
- return( n );
- }
-
-
-
- int
- CountSamePixels( p, bpp, pixCnt )
- char *p;
- int bpp;
- int pixCnt;
- {
- unsigned long pixel;
- unsigned long nextPixel;
- int n;
-
- n = 1;
- pixel = GetPixel( p, bpp );
- pixCnt--;
- while ( pixCnt > 0 )
- {
- p += bpp;
- nextPixel = GetPixel( p, bpp );
- if ( nextPixel != pixel ) break;
- ++n;
- --pixCnt;
- }
- return( n );
- }
-
-
-
- int
- CreatePostageStamp( fp, isp, sp )
- FILE *fp;
- TGAFile *isp;
- TGAFile *sp;
- {
- int i;
- int j;
- int dx, dy;
- int dxAdj;
- int imageXAdj, imageYAdj;
- int maxY;
- int bufSize;
- int bytesPerPixel;
- int stampSize;
- long int fileOffset;
- unsigned char *p, *q;
- unsigned char *rowBuf;
-
- /*
- ** Create a postage stamp if reasonable to do so...
- ** Since the postage stamp size is set to 64 x 64, we
- ** require the image to be at least twice this resolution
- ** before it makes sense to increase the file size by 50%.
- ** The handling of run length encoded data also represents
- ** a more troublesome problem.
- */
- if ( sp->imageWidth > 127 && sp->imageHeight > 127 )
- {
- /*
- ** The postage stamp is created by sampling the image data.
- ** The adjustment values cause the samples to be taken from
- ** the middle of the skipped range, as well as from the middle
- ** of the image.
- */
- dx = sp->imageWidth >> 6;
- dxAdj = dx >> 1;
- imageXAdj = ( sp->imageWidth % 64 ) >> 1;
- dy = sp->imageHeight >> 6;
- imageYAdj = ( sp->imageHeight % 64 ) >> 1;
- maxY = 64 * dy + imageYAdj;
-
- bytesPerPixel = ( sp->pixelDepth + 7 ) >> 3;
- bufSize = bytesPerPixel * sp->imageWidth;
-
- stampSize = 64 * 64 * bytesPerPixel;
- if ( ( sp->postStamp = malloc( stampSize ) ) == NULL )
- return( -1 );
- memset( sp->postStamp, 0, stampSize );
- fileOffset = 18 + isp->idLength +
- ((isp->mapWidth + 7) >> 3) * (long)isp->mapLength;
- if ( fseek( fp, fileOffset, SEEK_SET ) != 0 ) return( -1 );
-
- if ( ( rowBuf = malloc( bufSize ) ) != NULL )
- {
- q = sp->postStamp;
- for ( i = 0; i < maxY; ++i )
- {
- if ( sp->imageType > 0 && sp->imageType < 4 )
- {
- fread( rowBuf, 1, bufSize, fp );
- }
- else if ( sp->imageType > 8 && sp->imageType < 12 )
- {
- if ( ReadRLERow( rowBuf, bufSize, bytesPerPixel, fp ) < 0 )
- {
- puts( "Error reading RLE data during stamp creation." );
- return( -1 );
- }
- }
- else
- {
- puts( "Unknown Image Type." );
- sp->stampOffset = NULL;
- return( -1 );
- }
- if ( i < imageYAdj || ((i - imageYAdj) % dy) ) continue;
- p = rowBuf + ( bytesPerPixel * (imageXAdj + dxAdj) );
- for ( j = 0; j < 64; ++j )
- {
- *q++ = *p;
- if ( bytesPerPixel > 1 ) *q++ = *(p + 1);
- if ( bytesPerPixel > 2 ) *q++ = *(p + 2);
- if ( bytesPerPixel > 3 ) *q++ = *(p + 3);
- p += dx * bytesPerPixel;
- }
- }
- free( rowBuf );
- sp->stampWidth = sp->stampHeight = 64;
- }
- else
- {
- puts( "Unable to create row buffer." );
- return( -1 );
- }
- }
- else
- {
- sp->stampOffset = NULL;
- }
- return( 0 );
- }
-
-
-
-
- int
- DisplayImageData( q, n, bpp )
- unsigned char *q;
- int n;
- int bpp;
- {
- long i;
- int j;
- unsigned char a, b, c;
-
- i = 0;
- while ( i < n )
- {
- printf( "%08lX: ", i );
- switch ( bpp )
- {
- case 4:
- for ( j = 0; j < 4; ++j )
- {
- printf( "%08lx ", *(unsigned long *)q );
- q += 4;
- }
- i += 16;
- break;
- case 3:
- for ( j = 0; j < 8; ++j )
- {
- a = *q++;
- b = *q++;
- c = *q++;
- printf( "%02x%02x%02x ", c, b, a );
- }
- i += 24;
- break;
- case 2:
- for ( j = 0; j < 8; ++j )
- {
- printf( "%04x ", *(unsigned int *)q );
- q += 2;
- }
- i += 16;
- break;
- default:
- for ( j = 0; j < 16; ++j )
- {
- printf( "%02x ", *(unsigned char *)q++ );
- }
- i += 16;
- break;
- }
- putchar( '\n' );
- }
- return( 0 );
- }
-
-
-
- int
- EditDecimalNumber( s, n, retVal, min, max, warning )
- char *s;
- long n;
- long *retVal;
- long min;
- long max;
- int warning;
- {
- int i;
- int c;
- char *p;
- char str[20];
-
- do
- {
- _clearscreen( _GCLEARSCREEN );
- puts( s );
- printf( "%ld\n\n", n );
- printf( "Enter new value (min = %ld, max = %ld), ESC for no change:\n",
- min, max );
- if ( warning ) puts( warnStr );
- p = str;
- memset( str, 0, 20 );
- for ( i = 0; i < 19; ++i )
- {
- c = getche();
- if ( c == '\033' )
- {
- putchar( '\n' );
- return( -1 );
- }
- if ( c == '\n' || c == '\r' )
- {
- putch( '\n' );
- if ( *str == '\0' ) return( -1 );
- break;
- }
- if ( c == '\b' )
- {
- if ( p > str ) --p;
- if ( i > 0 ) --i;
- *p = '\0';
- putch( ' ' );
- putch( '\b' );
- }
- else *p++ = (char)c;
- }
- *retVal = atol( str );
- } while ( *retVal < min || *retVal > max );
- return( 0 );
- }
-
-
-
- int
- EditHexNumber( s, n, retVal, min, max, warning )
- char *s;
- long n;
- unsigned long *retVal;
- long min;
- long max;
- int warning;
- {
- int i;
- int c;
- char *p;
- char str[20];
-
- do
- {
- _clearscreen( _GCLEARSCREEN );
- puts( s );
- printf( "%lx\n\n", n );
- printf( "Enter new hexadecimal value (min = %lx, max = %lx), ESC for no change:\n",
- min, max );
- if ( warning ) puts( warnStr );
- p = str;
- memset( str, 0, 20 );
- for ( i = 0; i < 19; ++i )
- {
- c = getche();
- if ( c == '\033' )
- {
- putchar( '\n' );
- return( -1 );
- }
- if ( c == '\n' || c == '\r' )
- {
- putch( '\n' );
- if ( *str == '\0' ) return( -1 );
- break;
- }
- if ( c == '\b' )
- {
- if ( p > str ) --p;
- if ( i > 0 ) --i;
- *p = '\0';
- putch( ' ' );
- putch( '\b' );
- }
- else *p++ = (char)c;
- }
- sscanf( str, "%lx", retVal );
- } while ( *retVal < min || *retVal > max );
- return( 0 );
- }
-
-
-
- int
- EditString( is, il, os, ol )
- char *is;
- int il;
- char *os;
- int ol;
- {
- int i;
- int c;
- char *p;
- char *q;
-
- q = is;
- for ( i = 0; i < il; ++i )
- {
- if ( i > 0 && (i % 80) == 0 ) putchar( '\n' );
- if ( *q ) putchar( *q );
- else break;
- ++q;
- }
- printf( "\n\nEnter new string (max %d characters), ESC for no change:\n", ol );
- p = os;
- for ( i = 0; i < ol; ++i )
- {
- c = getche();
- if ( c == '\033' )
- {
- putchar( '\n' );
- return( -1 );
- }
- if ( c == '\n' || c == '\r' )
- {
- putch( '\n' );
- /* remove blank string if found */
- c = strlen( is );
- if ( *os == '\0' && c > 0 && SkipBlank( is ) != (is + c) )
- return( -1 );
- break;
- }
- if ( c == '\b' )
- {
- if ( p > os ) --p;
- if ( i > 0 ) --i;
- *p = '\0';
- putch( ' ' );
- putch( '\b' );
- }
- else *p++ = (char)c;
- }
- return( 0 );
- }
-
-
-
- int
- EditTGAFields( sp )
- TGAFile *sp;
- {
- long value;
- char txt[256];
-
- if ( allFields )
- {
- if ( EditDecimalNumber( "Color Map Type:",
- (long)sp->mapType, &value, 0L, 1L, WARN ) == 0 )
- {
- sp->mapType = (UINT8)value;
- }
- if ( EditDecimalNumber( "Image Type:",
- (long)sp->imageType, &value, 0L, 11L, WARN ) == 0 )
- {
- sp->imageType = (UINT8)value;
- }
- if ( EditDecimalNumber( "Color Map Origin:",
- (long)sp->mapOrigin, &value, 0L, 65535L, WARN ) == 0 )
- {
- sp->mapOrigin = (UINT16)value;
- }
- if ( EditDecimalNumber( "Color Map Length:",
- (long)sp->mapLength, &value, 0L, 65535L, WARN ) == 0 )
- {
- sp->mapLength = (UINT16)value;
- }
- if ( EditDecimalNumber( "Color Map Entry Size:",
- (long)sp->mapWidth, &value, 0L, 32L, WARN ) == 0 )
- {
- sp->mapWidth = (UINT8)value;
- }
- if ( EditDecimalNumber( "Image X Origin:",
- (long)sp->xOrigin, &value, 0L, 65535L, NOWARN ) == 0 )
- {
- sp->xOrigin = (UINT16)value;
- }
- if ( EditDecimalNumber( "Image Y Origin:",
- (long)sp->yOrigin, &value, 0L, 65535L, NOWARN ) == 0 )
- {
- sp->yOrigin = (UINT16)value;
- }
- if ( EditDecimalNumber( "Image Width:",
- (long)sp->imageWidth, &value, 0L, 65535L, WARN ) == 0 )
- {
- sp->imageWidth = (UINT16)value;
- }
- if ( EditDecimalNumber( "Image Height:",
- (long)sp->imageHeight, &value, 0L, 65535L, WARN ) == 0 )
- {
- sp->imageHeight = (UINT16)value;
- }
- if ( EditDecimalNumber( "Pixel Depth:",
- (long)sp->pixelDepth, &value, 0L, 32L, WARN ) == 0 )
- {
- sp->pixelDepth = (UINT8)value;
- }
- if ( EditHexNumber( "Image Descriptor:",
- (long)sp->imageDesc, &value, 0L, 0xffL, NOWARN ) == 0 )
- {
- sp->imageDesc = (UINT8)value;
- }
- }
-
- memset( txt, 0, 256 );
- _clearscreen( _GCLEARSCREEN );
- puts( "Current ID String:" );
- if ( EditString( sp->idString, sp->idLength, txt, 255 ) == 0 )
- {
- strcpy( sp->idString, txt );
- sp->idLength = (UINT8)strlen( sp->idString );
- }
-
- /*
- ** If creating old TGA format output, no need to edit remaining
- ** fields...
- */
- if ( noExtend ) return( 0 );
-
- memset( txt, 0, 256 );
- _clearscreen( _GCLEARSCREEN );
- puts( "Author Name:" );
- if ( EditString( sp->author, strlen( sp->author), txt, 40 ) == 0 )
- {
- strcpy( sp->author, txt );
- }
- memset( txt, 0, 256 );
- _clearscreen( _GCLEARSCREEN );
- puts( "Author Comments (line 1):" );
- if ( EditString( &sp->authorCom[0][0], strlen( &sp->authorCom[0][0] ),
- txt, 80 ) == 0 )
- {
- strcpy( &sp->authorCom[0][0], txt );
- }
- memset( txt, 0, 256 );
- _clearscreen( _GCLEARSCREEN );
- puts( "Author Comments (line 2):" );
- if ( EditString( &sp->authorCom[1][0], strlen( &sp->authorCom[1][0] ),
- txt, 80 ) == 0 )
- {
- strcpy( &sp->authorCom[1][0], txt );
- }
- memset( txt, 0, 256 );
- _clearscreen( _GCLEARSCREEN );
- puts( "Author Comments (line 3):" );
- if ( EditString( &sp->authorCom[2][0], strlen( &sp->authorCom[2][0] ),
- txt, 80 ) == 0 )
- {
- strcpy( &sp->authorCom[2][0], txt );
- }
- memset( txt, 0, 256 );
- _clearscreen( _GCLEARSCREEN );
- puts( "Author Comments (line 4):" );
- if ( EditString( &sp->authorCom[3][0], strlen( &sp->authorCom[3][0] ),
- txt, 80 ) == 0 )
- {
- strcpy( &sp->authorCom[3][0], txt );
- }
-
- if ( EditDecimalNumber( "Date/Time Stamp (month):",
- (long)sp->month, &value, 0L, 12L, NOWARN ) == 0 )
- {
- sp->month = (UINT16)value;
- }
-
- if ( EditDecimalNumber( "Date/Time Stamp (day):",
- (long)sp->day, &value, 0L, 31L, NOWARN ) == 0 )
- {
- sp->day = (UINT16)value;
- }
-
- /*
- ** Minimum and maximum year values are rather arbitrary...
- */
- if ( EditDecimalNumber( "Date/Time Stamp (year):",
- (long)sp->year, &value, 1975L, 2200L, NOWARN ) == 0 )
- {
- sp->year = (UINT16)value;
- }
-
- if ( EditDecimalNumber( "Date/Time Stamp (hour):",
- (long)sp->hour, &value, 0L, 23L, NOWARN ) == 0 )
- {
- sp->hour = (UINT16)value;
- }
-
- if ( EditDecimalNumber( "Date/Time Stamp (minute):",
- (long)sp->minute, &value, 0L, 59L, NOWARN ) == 0 )
- {
- sp->minute = (UINT16)value;
- }
-
- if ( EditDecimalNumber( "Date/Time Stamp (second):",
- (long)sp->second, &value, 0L, 59L, NOWARN ) == 0 )
- {
- sp->second = (UINT16)value;
- }
- memset( txt, 0, 256 );
- _clearscreen( _GCLEARSCREEN );
- puts( "Job Name/ID:" );
- if ( EditString( sp->jobID, strlen( sp->jobID), txt, 40 ) == 0 )
- {
- strcpy( sp->jobID, txt );
- }
-
- if ( EditDecimalNumber( "Job Time (hours):",
- (long)sp->jobHours, &value, 0L, 65535L, NOWARN ) == 0 )
- {
- sp->jobHours = (UINT16)value;
- }
-
- if ( EditDecimalNumber( "Job Time (minutes):",
- (long)sp->jobMinutes, &value, 0L, 59L, NOWARN ) == 0 )
- {
- sp->jobMinutes = (UINT16)value;
- }
-
- if ( EditDecimalNumber( "Job Time (seconds):",
- (long)sp->jobSeconds, &value, 0L, 59L, NOWARN ) == 0 )
- {
- sp->jobSeconds = (UINT16)value;
- }
-
- memset( txt, 0, 256 );
- _clearscreen( _GCLEARSCREEN );
- puts( "Software ID:" );
- if ( EditString( sp->softID, strlen( sp->softID), txt, 40 ) == 0 )
- {
- strcpy( sp->softID, txt );
- }
-
- if ( EditDecimalNumber( "Software Version Number * 100:",
- (long)sp->versionNum, &value, 0L, 65535L, NOWARN ) == 0 )
- {
- sp->versionNum = (UINT16)value;
- }
-
- memset( txt, 0, 256 );
- _clearscreen( _GCLEARSCREEN );
- puts( "Software Version Letter:" );
- if ( EditString( &sp->versionLet, strlen( &sp->versionLet), txt, 1 ) == 0 )
- {
- sp->versionLet = txt[0];
- }
- if ( sp->versionLet == '\0' ) sp->versionLet = ' ';
-
- if ( EditHexNumber( "Key Color (ARGB):",
- sp->keyColor, (unsigned long *)&value, 0L, 0xffffffffL, NOWARN ) == 0 )
- {
- sp->keyColor = (UINT32)value;
- }
-
- if ( EditDecimalNumber( "Pixel Aspect Ratio Numerator (width):",
- (long)sp->pixNumerator, &value, 0L, 32767L, NOWARN ) == 0 )
- {
- sp->pixNumerator = (UINT16)value;
- }
-
- if ( EditDecimalNumber( "Pixel Aspect Ratio Denominator (height):",
- (long)sp->pixDenominator, &value, 0L, 32767L, NOWARN ) == 0 )
- {
- sp->pixDenominator = (UINT16)value;
- }
-
- if ( EditDecimalNumber( "Gamma Correction Ratio Numerator:",
- (long)sp->gammaNumerator, &value, 0L, 32767L, NOWARN ) == 0 )
- {
- sp->gammaNumerator = (UINT16)value;
- }
-
- if ( EditDecimalNumber( "Gamma Correction Ratio Denominator:",
- (long)sp->gammaDenominator, &value, 0L, 32767L, NOWARN ) == 0 )
- {
- sp->gammaDenominator = (UINT16)value;
- }
-
- if ( EditDecimalNumber( "Alpha Attributes Type:",
- (long)sp->alphaAttribute, &value, 0L, 255L, NOWARN ) == 0 )
- {
- sp->alphaAttribute = (UINT8)value;
- }
- /*
- ** Attempt to make the alpha descriptor fields consistent
- */
- if ( sp->alphaAttribute == 0 && (sp->imageDesc & 0xf) != 0 )
- {
- sp->alphaAttribute = 2;
- }
-
- return( 0 ); /* return 0 for success, -1 to abort */
- }
-
-
-
- /*
- ** Retrieve a pixel value from a buffer. The actual size and order
- ** of the bytes is not important since we are only using the value
- ** for comparisons with other pixels.
- */
-
- unsigned long
- GetPixel( p, bpp )
- unsigned char *p;
- int bpp; /* bytes per pixel */
- {
- unsigned long pixel;
-
- pixel = (unsigned long)*p++;
- while ( bpp-- > 1 )
- {
- pixel <<= 8;
- pixel |= (unsigned long)*p++;
- }
- return( pixel );
- }
-
-
-
- int
- OutputTGAFile( ifp, ofp, isp, sp, xTGA, isbp )
- FILE *ifp; /* input file pointer */
- FILE *ofp; /* output file pointer */
- TGAFile *isp; /* input TGA structure */
- TGAFile *sp; /* output TGA structure */
- int xTGA; /* flags input file as new TGA format */
- struct stat *isbp;
- {
- long byteCount;
- long imageByteCount;
- unsigned long fileOffset;
- int i;
- int bytesPerPixel;
-
- /*
- ** The output file was just opened, so the first data
- ** to be written is the standard header based on the
- ** original TGA specification.
- */
- if ( WriteByte( sp->idLength, ofp ) < 0 ) return( -1 );
- if ( WriteByte( sp->mapType, ofp ) < 0 ) return( -1 );
- if ( WriteByte( sp->imageType, ofp ) < 0 ) return( -1 );
- if ( WriteShort( sp->mapOrigin, ofp ) < 0 ) return( -1 );
- if ( WriteShort( sp->mapLength, ofp ) < 0 ) return( -1 );
- if ( WriteByte( sp->mapWidth, ofp ) < 0 ) return( -1 );
- if ( WriteShort( sp->xOrigin, ofp ) < 0 ) return( -1 );
- if ( WriteShort( sp->yOrigin, ofp ) < 0 ) return( -1 );
- if ( WriteShort( sp->imageWidth, ofp ) < 0 ) return( -1 );
- if ( WriteShort( sp->imageHeight, ofp ) < 0 ) return( -1 );
- if ( WriteByte( sp->pixelDepth, ofp ) < 0 ) return( -1 );
- if ( WriteByte( sp->imageDesc, ofp ) < 0 ) return( -1 );
- if ( sp->idLength )
- {
- if ( WriteStr( sp->idString, sp->idLength, ofp ) < 0 )
- return( -1 );
- }
- /*
- ** Now we need to copy the color map data from the input file
- ** to the output file.
- */
- byteCount = 18 + isp->idLength;
- if ( fseek( ifp, byteCount, SEEK_SET ) != 0 ) return( -1 );
- byteCount = ((isp->mapWidth + 7) >> 3) * (long)isp->mapLength;
- fileOffset = 18 + sp->idLength + byteCount;
- while ( byteCount > 0 )
- {
- if ( byteCount - CBUFSIZE < 0 )
- {
- fread( copyBuf, 1, (int)byteCount, ifp );
- if ( fwrite( copyBuf, 1, (int)byteCount, ofp ) != (int)byteCount )
- return( -1 );
- }
- else
- {
- fread( copyBuf, 1, CBUFSIZE, ifp );
- if ( fwrite( copyBuf, 1, CBUFSIZE, ofp ) != CBUFSIZE )
- return( -1 );
- }
- byteCount -= CBUFSIZE;
- }
- /*
- ** Similarly, the image data can now be copied.
- ** This gets a little trickier since the input image could
- ** be compressed or the file could be in the new TGA format...
- */
- bytesPerPixel = (isp->pixelDepth + 7) >> 3;
- if ( isp->imageType > 0 && isp->imageType < 4 )
- {
- byteCount = bytesPerPixel *
- (long)isp->imageWidth *
- (long)isp->imageHeight;
- }
- else if ( isp->imageType > 8 && isp->imageType < 12 )
- {
- imageByteCount = CountRLEData( ifp, isp->imageWidth,
- isp->imageHeight, bytesPerPixel );
- /* Recalculate offset to beginning of image data */
- byteCount = 18 + isp->idLength;
- byteCount += ((isp->mapWidth + 7) >> 3) * (long)isp->mapLength;
- if ( fseek( ifp, byteCount, SEEK_SET ) != 0 ) return( -1 );
- byteCount = imageByteCount;
- }
- else if ( !xTGA )
- {
- /*
- ** If the file is not an extended TGA file, we can
- ** calculate the image byte count based upon the size
- ** of the file (hopefully).
- */
- byteCount = 18 + isp->idLength;
- byteCount += ((isp->mapWidth + 7) >> 3) * (long)isp->mapLength;
- byteCount = isbp->st_size - byteCount;
- }
- else
- {
- puts( "Cannot determine amount of image data" );
- return( -1 );
- }
- fileOffset += byteCount;
- while ( byteCount > 0 )
- {
- if ( byteCount - CBUFSIZE < 0 )
- {
- fread( copyBuf, 1, (int)byteCount, ifp );
- if ( fwrite( copyBuf, 1, (int)byteCount, ofp ) != (int)byteCount )
- return( -1 );
- }
- else
- {
- fread( copyBuf, 1, CBUFSIZE, ifp );
- if ( fwrite( copyBuf, 1, CBUFSIZE, ofp ) != CBUFSIZE )
- return( -1 );
- }
- byteCount -= CBUFSIZE;
- }
-
- if ( noExtend ) return( 0 );
-
- /*
- ** Attempt to preserve developer area if it exists in the input file
- */
- if ( !noDev && isp->devDirOffset != NULL )
- {
- if ( (sp->devDirs = malloc( sp->devTags * sizeof(DevDir) ) ) == NULL )
- {
- puts( "Failed to allocate memory for new developer directory." );
- return( -1 );
- }
- for ( i = 0; i < sp->devTags; ++i )
- {
- if ( fseek( ifp, isp->devDirs[i].tagOffset, SEEK_SET ) != 0 )
- {
- puts( "Error seeking to developer entry." );
- free( sp->devDirs );
- return( -1 );
- }
- sp->devDirs[i].tagOffset = fileOffset;
- byteCount = isp->devDirs[i].tagSize;
- fileOffset += byteCount;
- while ( byteCount > 0 )
- {
- if ( byteCount - CBUFSIZE < 0 )
- {
- fread( copyBuf, 1, (int)byteCount, ifp );
- if ( fwrite( copyBuf, 1, (int)byteCount, ofp ) != (int)byteCount )
- return( -1 );
- }
- else
- {
- fread( copyBuf, 1, CBUFSIZE, ifp );
- if ( fwrite( copyBuf, 1, CBUFSIZE, ofp ) != CBUFSIZE )
- return( -1 );
- }
- byteCount -= CBUFSIZE;
- }
- }
- sp->devDirOffset = fileOffset;
- WriteShort( sp->devTags, ofp );
- byteCount = (long)sp->devTags * sizeof( DevDir );
- if ( (long)fwrite( sp->devDirs, 1, (int)byteCount, ofp ) != byteCount )
- {
- puts( "Error writing developer area." );
- free( sp->devDirs );
- return( -1 );
- }
- fileOffset += byteCount + 2;
- free( sp->devDirs );
- }
-
- /*
- ** Unlike the figure in the specification, we will output
- ** the scan line table, the postage stamp, and the color
- ** correction table before we output the extension area.
- ** This simply makes the calculation of the offset values
- ** easier to manage...
- ** Copy the scan line table from the input file to
- ** the output file. A future version could create the table
- ** if it does not already exist.
- */
- if ( !noScan && isp->scanLineOffset != 0L )
- {
- if ( fseek( ifp, isp->scanLineOffset, SEEK_SET ) != 0 )
- return( -1 );
- sp->scanLineOffset = fileOffset;
- for ( i = 0; i < sp->imageHeight; ++i )
- {
- if ( WriteLong( ReadLong( ifp ), ofp ) < 0 ) return( -1 );
- }
- fileOffset += sp->imageHeight * sizeof( UINT32 );
- }
-
- /*
- ** Either copy the postage stamp from the input file to
- ** the output file, or create one.
- */
- if ( !noStamp )
- {
- if ( isp->stampOffset != NULL )
- {
- if ( fseek( ifp, isp->stampOffset, SEEK_SET ) != 0 )
- return( -1 );
- /*
- ** Since postage stamps are uncompressed, calculation
- ** of its size is straight forward.
- */
- byteCount = bytesPerPixel *
- (long)isp->stampWidth *
- (long)isp->stampHeight + 2;
-
- sp->stampOffset = fileOffset;
- fileOffset += byteCount;
- while ( byteCount > 0 )
- {
- if ( byteCount - CBUFSIZE < 0 )
- {
- fread( copyBuf, 1, (int)byteCount, ifp );
- if ( fwrite( copyBuf, 1, (int)byteCount, ofp ) != (int)byteCount )
- return( -1 );
- }
- else
- {
- fread( copyBuf, 1, CBUFSIZE, ifp );
- if ( fwrite( copyBuf, 1, CBUFSIZE, ofp ) != CBUFSIZE )
- return( -1 );
- }
- byteCount -= CBUFSIZE;
- }
- }
- else
- {
- if ( (isp->imageType > 0 && isp->imageType < 4 ) ||
- (isp->imageType > 8 && isp->imageType < 12 ) )
- {
- if ( CreatePostageStamp( ifp, isp, sp ) >= 0 && sp->postStamp )
- {
- sp->stampOffset = fileOffset;
- WriteByte( sp->stampWidth, ofp );
- WriteByte( sp->stampHeight, ofp );
- i = sp->stampWidth * sp->stampHeight *
- bytesPerPixel;
- fileOffset += i + 2;
- if ( fwrite( sp->postStamp, 1, i, ofp ) != i )
- {
- puts( "Error writing postage stamp." );
- return( -1 );
- }
- }
- else
- {
- if ( sp->postStamp )
- puts( "Error creating postage stamp." );
- else
- puts( "Image size too small for stamp" );
- return( -1 );
- }
- }
- else
- {
- puts( "Do not know how to create postage stamp." );
- }
- }
- }
- else sp->stampOffset = 0L;
-
- /*
- ** Next copy the Color Correction Table to the output file
- */
- if ( !noColor && sp->colorCorrectTable != NULL )
- {
- sp->colorCorrectOffset = fileOffset;
- if ( WriteColorTable( ofp, sp ) < 0 ) return( -1 );
- fileOffset += 1024 * sizeof(UINT16);
- }
-
- /*
- ** Output TGA extension area - version 2.0 format
- */
- sp->extAreaOffset = fileOffset;
- if ( WriteShort( EXT_SIZE_20, ofp ) < 0 ) return( -1 );
- if ( WriteStr( sp->author, 41, ofp ) < 0 ) return( -1 );
- if ( WriteStr( &sp->authorCom[0][0], 81, ofp ) < 0 ) return( -1 );
- if ( WriteStr( &sp->authorCom[1][0], 81, ofp ) < 0 ) return( -1 );
- if ( WriteStr( &sp->authorCom[2][0], 81, ofp ) < 0 ) return( -1 );
- if ( WriteStr( &sp->authorCom[3][0], 81, ofp ) < 0 ) return( -1 );
- if ( WriteShort( sp->month, ofp ) < 0 ) return( -1 );
- if ( WriteShort( sp->day, ofp ) < 0 ) return( -1 );
- if ( WriteShort( sp->year, ofp ) < 0 ) return( -1 );
- if ( WriteShort( sp->hour, ofp ) < 0 ) return( -1 );
- if ( WriteShort( sp->minute, ofp ) < 0 ) return( -1 );
- if ( WriteShort( sp->second, ofp ) < 0 ) return( -1 );
- if ( WriteStr( sp->jobID, 41, ofp ) < 0 ) return( -1 );
- if ( WriteShort( sp->jobHours, ofp ) < 0 ) return( -1 );
- if ( WriteShort( sp->jobMinutes, ofp ) < 0 ) return( -1 );
- if ( WriteShort( sp->jobSeconds, ofp ) < 0 ) return( -1 );
- if ( WriteStr( sp->softID, 41, ofp ) < 0 ) return( -1 );
- if ( WriteShort( sp->versionNum, ofp ) < 0 ) return( -1 );
- if ( sp->versionLet == '\0' ) sp->versionLet = ' ';
- if ( WriteByte( sp->versionLet, ofp ) < 0 ) return( -1 );
- if ( WriteLong( sp->keyColor, ofp ) < 0 ) return( -1 );
- if ( WriteShort( sp->pixNumerator, ofp ) < 0 ) return( -1 );
- if ( WriteShort( sp->pixDenominator, ofp ) < 0 ) return( -1 );
- if ( WriteShort( sp->gammaNumerator, ofp ) < 0 ) return( -1 );
- if ( WriteShort( sp->gammaDenominator, ofp ) < 0 ) return( -1 );
- if ( WriteLong( sp->colorCorrectOffset, ofp ) < 0 ) return( -1 );
- if ( WriteLong( sp->stampOffset, ofp ) < 0 ) return( -1 );
- if ( WriteLong( sp->scanLineOffset, ofp ) < 0 ) return( -1 );
- if ( WriteByte( sp->alphaAttribute, ofp ) < 0 ) return( -1 );
-
- /*
- ** For now, simply output extended tag info
- */
- if ( WriteLong( sp->extAreaOffset, ofp ) < 0 ) return( -1 );
- if ( WriteLong( sp->devDirOffset, ofp ) < 0 ) return( -1 );
- if ( WriteStr( "TRUEVISION-XFILE.\0", 18, ofp ) < 0 ) return( -1 );
- return( 0 );
- }
-
-
-
- int
- ParseArgs( argc, argv )
- int argc;
- char **argv;
- {
- int i;
- int n;
- char *p;
-
- n = 0;
- for ( i = 1; i < argc; ++i )
- {
- p = *(++argv);
- if ( *p == '-' )
- {
- p++;
- if ( stricmp( p, "noprompt" ) == 0 ) noPrompt = 1;
- else if ( stricmp( p, "nostamp" ) == 0 ) noStamp = 1;
- else if ( stricmp( p, "all" ) == 0 ) allFields = 1;
- else if ( stricmp( p, "noextend" ) == 0 ) noExtend = 1;
- else if ( stricmp( p, "nodev" ) == 0 ) noDev = 1;
- else if ( stricmp( p, "nocolor" ) == 0 ) noColor = 1;
- else if ( stricmp( p, "noscan" ) == 0 ) noScan = 1;
- else if ( stricmp( p, "version" ) == 0 )
- {
- puts( versionStr );
- exit( 0 );
- }
- else
- {
- puts( "Usage: tgaedit [options] [file1] [file2...]" );
- puts( " where options can be:" );
- puts( " -noprompt\t\tprocess without prompting for changes" );
- puts( " -nostamp\t\tsuppress postage stamp" );
- puts( " -nodev\t\tsuppress developer area" );
- puts( " -nocolor\t\tsuppress color correction table" );
- puts( " -noscan\t\tsuppress scan line offset table" );
- puts( " -all\t\tallow editing of all TGA fields" );
- puts( " -noextend\t\toutput old TGA format" );
- puts( " -version\t\treport version number" );
- exit( 0 );
- }
- }
- else ++n;
- }
- return( n );
- }
-
-
- void
- PrintColorTable( sp )
- TGAFile *sp;
- {
- unsigned int n;
- UINT16 *p;
-
- puts( "Color Correction Table:" );
- p = sp->colorCorrectTable;
- for ( n = 0; n < 256; ++n )
- {
- printf( "Color Entry %3u: 0x%04x(%5u) A, ", n, *p, *p );
- ++p;
- printf( "0x%04x(%5u) R, ", *p, *p );
- ++p;
- printf( "0x%04x(%5u) G, ", *p, *p );
- ++p;
- printf( "0x%04x(%5u) B\n", *p, *p );
- ++p;
- }
- }
-
-
-
- void
- PrintExtendedTGA( sp )
- TGAFile *sp; /* TGA structure pointer */
- {
- register int strSize;
- char *blankChars = " \t";
-
- puts( "***** Extended TGA Fields *****" );
- printf( "Truevision TGA File Format Version: " );
- if ( sp->extSize == EXT_SIZE_20 ) puts( "2.0" );
- else printf( "UNKNOWN, extension size = %d\n", sp->extSize );
-
- /*
- ** Make sure the strings have length, and contain something
- ** other than blanks and tabs
- */
- strSize = strlen( sp->author );
- if ( strSize && strspn( sp->author, blankChars ) < strSize )
- {
- printf( "Author: %s\n", sp->author );
- }
- strSize = strlen( &sp->authorCom[0][0] );
- if ( strSize && strspn( &sp->authorCom[0][0], blankChars ) < strSize )
- {
- puts( "Author Comments:" );
- puts( &sp->authorCom[0][0] );
- strSize = strlen( &sp->authorCom[1][0] );
- if ( strSize && strspn( &sp->authorCom[1][0], blankChars ) < strSize )
- {
- puts( &sp->authorCom[1][0] );
- }
- strSize = strlen( &sp->authorCom[2][0] );
- if ( strSize && strspn( &sp->authorCom[2][0], blankChars ) < strSize )
- {
- puts( &sp->authorCom[2][0] );
- }
- strSize = strlen( &sp->authorCom[3][0] );
- if ( strSize && strspn( &sp->authorCom[3][0], blankChars ) < strSize )
- {
- puts( &sp->authorCom[3][0] );
- }
- puts( "[End of Author Comments]" );
- }
-
- if ( sp->month )
- {
- printf( "Date Image Saved: " );
- PrintMonth( sp->month );
- printf( " %02u, %4u at %02u:%02u:%02u\n", sp->day, sp->year,
- sp->hour, sp->minute, sp->second );
- }
-
- strSize = strlen( sp->jobID );
- if ( strSize && strspn( sp->jobID, blankChars ) < strSize )
- {
- printf( "Job Name/ID: %s\n", sp->jobID );
- }
-
- if ( sp->jobHours != 0 || sp->jobMinutes != 0 || sp->jobSeconds != 0 )
- {
- printf( "Job Elapsed Time: %02u:%02u:%02u\n", sp->jobHours,
- sp->jobMinutes, sp->jobSeconds );
- }
-
- strSize = strlen( sp->softID );
- if ( strSize && strspn( sp->softID, blankChars ) < strSize )
- {
- printf( "Software ID: %s\n", sp->softID );
- }
-
- if ( sp->versionNum != 0 || sp->versionLet != ' ' )
- {
- printf( "Software Version: %u.%u%c\n", sp->versionNum/100,
- sp->versionNum % 100, sp->versionLet );
- }
-
- printf( "Key Color: 0x%02lx(%ld) Alpha, 0x%02lx(%ld) Red, 0x%02lx(%ld) Green, 0x%02lx(%ld) Blue\n",
- sp->keyColor >> 24, sp->keyColor >> 24,
- (sp->keyColor >> 16) & 0xff, (sp->keyColor >> 16) & 0xff,
- (sp->keyColor >> 8) & 0xff, (sp->keyColor >> 8) & 0xff,
- sp->keyColor & 0xff, sp->keyColor & 0xff );
-
- if ( sp->pixNumerator != 0 && sp->pixDenominator != 0 )
- {
- printf( "Pixel Aspect Ratio: %f\n", (double)sp->pixNumerator /
- (double)sp->pixDenominator );
- }
-
- if ( sp->gammaDenominator != 0 )
- {
- printf( "Gamma Correction: %f\n", (double)sp->gammaNumerator /
- (double)sp->gammaDenominator );
- }
-
- printf( "Color Correction Offset = 0x%08lx\n", sp->colorCorrectOffset );
- if ( sp->colorCorrectOffset && sp->colorCorrectTable )
- {
- PrintColorTable( sp );
- }
- printf( "Postage Stamp Offset = 0x%08lx\n", sp->stampOffset );
- if ( sp->stampOffset )
- {
- printf( "Postage Stamp Width, Height: %3u, %3u\n",
- sp->stampWidth, sp->stampHeight );
- }
- printf( "Scan Line Offset = 0x%08lx\n", sp->scanLineOffset );
- if ( sp->scanLineOffset && sp->scanLineTable )
- {
- PrintScanLineTable( sp );
- }
-
- switch (sp->alphaAttribute )
- {
- case 0:
- if ( (sp->imageDesc & 0xf) == 0 ) puts( "No Alpha Data Present" );
- else puts( "Inconsistent Alpha Data Specification" );
- break;
- case 1:
- puts( "Alpha Data Undefined and Can Be Ignored" );
- break;
- case 2:
- puts( "Alpha Data Undefined but Should Be Retained" );
- break;
- case 3:
- puts( "Useful Alpha Data Present" );
- break;
- case 4:
- puts( "Pre-Multiplied Alpha Data Present" );
- break;
- default:
- puts( "Undefined Alpha Attribute Field" );
- break;
- }
- }
-
-
-
- void
- PrintImageType( Itype )
- register int Itype;
- {
- if ( Itype > 255 || Itype < 0 )
- {
- puts("Illegal/Undefined Image Type");
- return;
- }
-
- if ( Itype > 127 )
- {
- puts("Unknown Image Type - Application Specific");
- return;
- }
-
- switch (Itype)
- {
- case 0:
- puts("Unknown Image Type - No Image Data Present");
- break;
- case 1:
- puts("Uncompressed Color Mapped Image (e.g., VDA/D, TARGA M8)");
- break;
- case 2:
- puts("Uncompressed True Color Image (e.g., ICB, TARGA 16/24/32)");
- break;
- case 3:
- puts("Uncompressed Black & White Image (e.g., TARGA 8/M8)");
- break;
- case 9:
- puts("Run Length Encoded Color Mapped Image (e.g., VDA/D, TARGA M8)");
- break;
- case 10:
- puts("Run Length Encoded True Color Image (e.g., ICB, TARGA 16/24/32)");
- break;
- case 11:
- puts("Compressed Black & White Image (e.g., TARGA 8/M8)");
- break;
- case 32:
- case 34:
- puts("Compressed (Huffman/Delta/RLE) Color Mapped Image (e.g., VDA/D) - Obsolete");
- break;
- case 33:
- case 35:
- puts("Compressed (Huffman/Delta/RLE) Color Mapped Four Pass Image (e.g., VDA/D) - Obsolete");
- break;
- default:
- puts("Unknown Image Type");
- break;
- }
- }
-
-
- void
- PrintMonth( month )
- UINT16 month;
- {
- if ( month > 0 && month < 13 ) printf( monthStr[month - 1] );
- else printf( "Month Error" );
- }
-
-
- void
- PrintScanLineTable( sp )
- TGAFile *sp;
- {
- UINT16 n;
- UINT32 *p;
-
- puts( "Scan Line Table:" );
- p = sp->scanLineTable;
- for ( n = 0; n < sp->imageHeight; ++n )
- {
- printf( "Scan Line %6u, Offset 0x%08lx(%8d)\n", n, *p, *p );
- ++p;
- }
- }
-
-
-
- void
- PrintTGAInfo( sp )
- TGAFile *sp; /* TGA structure pointer */
- {
- int i;
-
- printf("ID Field Length = %3d\n", sp->idLength);
-
- printf("Color Map Type = %3d (Color Map Data is ", sp->mapType);
- if (sp->mapType) puts("Present)");
- else puts("Absent)");
-
- printf("Image Type = %3d\n ", sp->imageType);
- PrintImageType( sp->imageType );
-
- printf("Color Map Origin = 0x%04x (%5d)",
- sp->mapOrigin, sp->mapOrigin);
- puts( " (First Index To Be Loaded)" );
- printf("Color Map Length = 0x%04x (%5d)\n",
- sp->mapLength,sp->mapLength);
- printf("Color Map Entry Size = %6d\n", sp->mapWidth);
-
- printf("Image X-Origin, Y-Origin = %05d, %05d\n",
- sp->xOrigin, sp->yOrigin);
- printf("Image Width, Height = %05d, %05d\n",
- sp->imageWidth, sp->imageHeight);
-
- printf("Image Pixel Depth = 0x%04x (%05d)\n",
- sp->pixelDepth, sp->pixelDepth);
- printf("Image Descriptor = 0x%04x\n", sp->imageDesc);
- printf(" %d Attribute Bits Per Pixel\n", sp->imageDesc & 0xf );
- printf(" First Pixel Destination is ");
-
- i = (sp->imageDesc & 0x30) >> 4;
- puts( orientStr[i] );
-
- i = (sp->imageDesc & 0xc0) >> 6;
- if ( i > 0 && i < 3 ) puts( interleaveStr[i - 1] );
-
- if ( sp->idLength )
- {
- printf( "Image ID:\n " );
- puts( f.idString );
- }
- }
-
-
- UINT8
- ReadByte( fp )
- FILE *fp;
- {
- UINT8 value;
-
- #if MSDOS
- fread( &value, 1, 1, fp );
- #else
- #endif
- return( value );
- }
-
-
- void
- ReadCharField( fp, p, n )
- FILE *fp;
- char *p;
- int n;
- {
- while ( n )
- {
- *p++ = (char)fgetc( fp ); /* no error check, no char conversion */
- --n;
- }
- }
-
-
- int
- ReadColorTable( fp, sp )
- FILE *fp;
- TGAFile *sp;
- {
- UINT16 *p;
- UINT16 n;
-
- if ( !fseek( fp, sp->colorCorrectOffset, SEEK_SET ) )
- {
- if ( sp->colorCorrectTable = malloc( 1024 * sizeof( UINT16 ) ) )
- {
- p = sp->colorCorrectTable;
- for ( n = 0; n < 1024; ++n )
- {
- *p++ = ReadShort( fp );
- }
- }
- else
- {
- puts( "Unable to allocate Color Correction Table." );
- return( -1 );
- }
- }
- else
- {
- printf( "Error seeking to Color Correction Table, offset = 0x%08lx\n",
- sp->colorCorrectOffset );
- return( -1 );
- }
- return( 0 );
- }
-
-
-
- int
- ReadDeveloperDirectory( fp, sp )
- FILE *fp;
- TGAFile *sp;
- {
- int i;
-
- if ( !fseek( fp, sp->devDirOffset, SEEK_SET ) )
- {
- sp->devTags = ReadShort( fp );
- if ( (sp->devDirs = malloc( sp->devTags * sizeof(DevDir) )) == NULL )
- {
- puts( "Unable to allocate developer directory." );
- return( -1 );
- }
- for ( i = 0; i < sp->devTags; ++i )
- {
- sp->devDirs[i].tagValue = ReadShort( fp );
- sp->devDirs[i].tagOffset = ReadLong( fp );
- sp->devDirs[i].tagSize = ReadLong( fp );
- }
- }
- else
- {
- printf( "Error seeking to Developer Area at offset 0x%08lx\n",
- sp->devDirOffset );
- return(-1);
- }
- return( 0 );
- }
-
-
-
- int
- ReadExtendedTGA( fp, sp )
- FILE *fp;
- TGAFile *sp;
- {
- if ( !fseek( fp, sp->extAreaOffset, SEEK_SET ) )
- {
- sp->extSize = ReadShort( fp );
- memset( sp->author, 0, 41 );
- ReadCharField( fp, sp->author, 41 );
- memset( &sp->authorCom[0][0], 0, 81 );
- ReadCharField( fp, &sp->authorCom[0][0], 81 );
- memset( &sp->authorCom[1][0], 0, 81 );
- ReadCharField( fp, &sp->authorCom[1][0], 81 );
- memset( &sp->authorCom[2][0], 0, 81 );
- ReadCharField( fp, &sp->authorCom[2][0], 81 );
- memset( &sp->authorCom[3][0], 0, 81 );
- ReadCharField( fp, &sp->authorCom[3][0], 81 );
-
- sp->month = ReadShort( fp );
- sp->day = ReadShort( fp );
- sp->year = ReadShort( fp );
- sp->hour = ReadShort( fp );
- sp->minute = ReadShort( fp );
- sp->second = ReadShort( fp );
-
- memset( sp->jobID, 0, 41 );
- ReadCharField( fp, sp->jobID, 41 );
- sp->jobHours = ReadShort( fp );
- sp->jobMinutes = ReadShort( fp );
- sp->jobSeconds = ReadShort( fp );
-
- memset( sp->softID, 0, 41 );
- ReadCharField( fp, sp->softID, 41 );
- sp->versionNum = ReadShort( fp );
- sp->versionLet = ReadByte( fp );
-
- sp->keyColor = ReadLong( fp );
- sp->pixNumerator = ReadShort( fp );
- sp->pixDenominator = ReadShort( fp );
-
- sp->gammaNumerator = ReadShort( fp );
- sp->gammaDenominator = ReadShort( fp );
-
- sp->colorCorrectOffset = ReadLong( fp );
- sp->stampOffset = ReadLong( fp );
- sp->scanLineOffset = ReadLong( fp );
-
- sp->alphaAttribute = ReadByte( fp );
-
- sp->colorCorrectTable = (UINT16 *)0;
- if ( sp->colorCorrectOffset )
- {
- ReadColorTable( fp, sp );
- }
-
- sp->postStamp = (void *)0;
- if ( sp->stampOffset )
- {
- if ( !fseek( fp, sp->stampOffset, SEEK_SET ) )
- {
- sp->stampWidth = ReadByte( fp );
- sp->stampHeight = ReadByte( fp );
- /*
- ** Leave the processing of postage stamp data to
- ** the output phase of the program. All we really
- ** need to know is whether it exists in the input file.
- */
- }
- else
- {
- printf( "Error seeking to Postage Stamp, offset = 0x%08lx\n",
- sp->stampOffset );
- }
- }
-
- sp->scanLineTable = (UINT32 *)0;
- if ( sp->scanLineOffset )
- {
- ReadScanLineTable( fp, sp );
- }
- }
- else
- {
- printf( "Error seeking to Extended TGA Area, offset = 0x%08lx\n",
- sp->extAreaOffset );
- return( -1 );
- }
- return( 0 );
- }
-
-
- UINT32
- ReadLong( fp )
- FILE *fp;
- {
- UINT32 value;
-
- #if MSDOS
- fread( &value, 4, 1, fp );
- #else
- #endif
- return( value );
- }
-
-
-
- int
- ReadRLERow( p, n, bpp, fp )
- unsigned char *p;
- int n; /* buffer size in bytes */
- int bpp; /* bytes per pixel */
- FILE *fp;
- {
- unsigned int value;
- int i;
- unsigned char *q;
-
- while ( n > 0 )
- {
- value = (unsigned int)ReadByte( fp );
- if ( value & 0x80 )
- {
- value &= 0x7f;
- value++;
- n -= value * bpp;
- if ( n < 0 ) return( -1 );
- if ( fread( rleBuf, 1, bpp, fp ) != bpp ) return( -1 );
- while ( value > 0 )
- {
- *p++ = rleBuf[0];
- if ( bpp > 1 ) *p++ = rleBuf[1];
- if ( bpp > 2 ) *p++ = rleBuf[2];
- if ( bpp > 3 ) *p++ = rleBuf[3];
- value--;
- }
- }
- else
- {
- value++;
- n -= value * bpp;
- if ( n < 0 ) return( -1 );
- /*
- ** Maximum for value is 128 so as long as RLEBUFSIZ
- ** is at least 512, and bpp is not greater than 4
- ** we can read in the entire raw packet with one operation.
- */
- if ( fread( rleBuf, bpp, value, fp ) != value ) return( -1 );
- for ( i = 0, q = rleBuf; i < (value * bpp); ++i ) *p++ = *q++;
- }
- }
- return( 0 );
- }
-
-
-
- int
- ReadScanLineTable( fp, sp )
- FILE *fp;
- TGAFile *sp;
- {
- UINT32 *p;
- UINT16 n;
-
- if ( !fseek( fp, sp->scanLineOffset, SEEK_SET ) )
- {
- if ( sp->scanLineTable = malloc( sp->imageHeight << 2 ) )
- {
- p = sp->scanLineTable;
- for ( n = 0; n < sp->imageHeight; ++n )
- {
- *p++ = ReadShort( fp );
- }
- }
- else
- {
- puts( "Unable to allocate Scan Line Table." );
- return( -1 );
- }
- }
- else
- {
- printf( "Error seeking to Scan Line Table, offset = 0x%08lx\n",
- sp->scanLineOffset );
- return( -1 );
- }
- return( 0 );
- }
-
-
- UINT16
- ReadShort( fp )
- FILE *fp;
- {
- UINT16 value;
-
- #if MSDOS
- fread( &value, 2, 1, fp );
- #else
- #endif
- return( value );
- }
-
-
-
- int
- RLEncodeRow( p, q, n, bpp )
- char *p; /* data to be encoded */
- char *q; /* encoded buffer */
- int n; /* number of pixels in buffer */
- int bpp; /* bytes per pixel */
- {
- int diffCount; /* pixel count until two identical */
- int sameCount; /* number of identical adjacent pixels */
- int RLEBufSize; /* count of number of bytes encoded */
-
- RLEBufSize = 0;
- while ( n > 0 )
- {
- diffCount = CountDiffPixels( p, bpp, n );
- sameCount = CountSamePixels( p, bpp, n );
- if ( diffCount > 128 ) diffCount = 128;
- if ( sameCount > 128 ) sameCount = 128;
- if ( diffCount > 0 )
- {
- /* create a raw packet */
- *q++ = (char)(diffCount - 1);
- n -= diffCount;
- RLEBufSize += (diffCount * bpp) + 1;
- while ( diffCount > 0 )
- {
- *q++ = *p++;
- if ( bpp > 1 ) *q++ = *p++;
- if ( bpp > 2 ) *q++ = *p++;
- if ( bpp > 3 ) *q++ = *p++;
- diffCount--;
- }
- }
- if ( sameCount > 1 )
- {
- /* create a RLE packet */
- *q++ = (char)((sameCount - 1) | 0x80);
- n -= sameCount;
- RLEBufSize += bpp + 1;
- p += (sameCount - 1) * bpp;
- *q++ = *p++;
- if ( bpp > 1 ) *q++ = *p++;
- if ( bpp > 2 ) *q++ = *p++;
- if ( bpp > 3 ) *q++ = *p++;
- }
- }
- return( RLEBufSize );
- }
-
-
-
- char *
- SkipBlank( p )
- char *p;
- {
- while ( *p != '\0' && (*p == ' ' || *p == '\t') ) ++p;
- return( p );
- }
-
-
- int
- WriteByte( uc, fp )
- UINT8 uc;
- FILE *fp;
- {
- #ifdef MSDOS
- if ( fwrite( &uc, 1, 1, fp ) == 1 ) return( 0 );
- #else
- #endif
- return( -1 );
- }
-
-
- int
- WriteColorTable( fp, sp )
- FILE *fp;
- TGAFile *sp;
- {
- UINT16 *p;
- UINT16 n;
-
- p = sp->colorCorrectTable;
- for ( n = 0; n < 1024; ++n )
- {
- if ( WriteShort( *p++, fp ) < 0 ) return( -1 );
- }
- return( 0 );
- }
-
-
- int
- WriteLong( ul, fp )
- UINT32 ul;
- FILE *fp;
- {
- #ifdef MSDOS
- if ( fwrite( &ul, 4, 1, fp ) == 1 ) return( 0 );
- #else
- #endif
- return( -1 );
- }
-
-
- int
- WriteShort( us, fp )
- UINT16 us;
- FILE *fp;
- {
- #ifdef MSDOS
- if ( fwrite( &us, 2, 1, fp ) == 1 ) return( 0 );
- #else
- #endif
- return( -1 );
- }
-
-
- int
- WriteStr( p, n, fp )
- char *p;
- int n;
- FILE *fp;
- {
- #ifdef MSDOS
- if ( fwrite( p, 1, n, fp ) == n ) return( 0 );
- #else
- #endif
- return( -1 );
- }
-