home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
World of Shareware - Software Farm 2
/
wosw_2.zip
/
wosw_2
/
CPROG
/
TGAUTL.ZIP
/
TGAEDIT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-03-26
|
54KB
|
2,212 lines
/*
** 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 );
}