home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Resource Library: Graphics
/
graphics-16000.iso
/
general
/
convrtrs
/
pbmplus
/
ntpbmsrc.lha
/
netpbm
/
ppm
/
ppmtotga.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-04
|
11KB
|
454 lines
/* ppmtotga.c - read a portable pixmap and produce a TrueVision Targa file
**
** Copyright (C) 1989, 1991 by Mark Shand and Jef Poskanzer
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation. This software is provided "as is" without express or
** implied warranty.
*/
#include "ppm.h"
#include "ppmcmap.h"
#include "tga.h"
/* Max number of colors allowed for colormapped output. */
#define MAXCOLORS 256
/* Forward routines. */
static void writetga ARGS(( struct ImageHeader* tgaP, char* id ));
static void put_map_entry ARGS(( pixel* valueP, int size, pixval maxval ));
static void compute_runlengths ARGS(( int cols, pixel* pixelrow, int* runlength ));
static void put_pixel ARGS(( pixel* pP, int imgtype, pixval maxval, colorhash_table cht ));
static void put_mono ARGS(( pixel* pP, pixval maxval ));
static void put_map ARGS(( pixel* pP, colorhash_table cht ));
static void put_rgb ARGS(( pixel* pP, pixval maxval ));
/* Routines. */
int
main( argc, argv )
int argc;
char* argv[];
{
FILE* ifp;
pixel** pixels;
register pixel* pP;
pixel p;
int argn, rle_flag, rows, cols, ncolors, row, col, i, format, realrow;
pixval maxval;
colorhist_vector chv;
colorhash_table cht;
char out_name[100];
char* cp;
int* runlength;
char* usage = "[-name <tganame>] [-mono|-cmap|-rgb] [-norle] [ppmfile]";
struct ImageHeader tgaHeader;
ppm_init( &argc, argv );
out_name[0] = '\0';
/* Check for command line options. */
argn = 1;
tgaHeader.ImgType = TGA_Null;
rle_flag = 1;
/* Check for command line options. */
while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
{
if ( pm_keymatch( argv[argn], "-name", 2 ) )
{
++argn;
if ( argn == argc )
pm_usage( usage );
(void) strcpy( out_name, argv[argn] );
}
else if ( pm_keymatch( argv[argn], "-cmap", 2 ) )
tgaHeader.ImgType = TGA_Map;
else if ( pm_keymatch( argv[argn], "-mono", 2 ) )
tgaHeader.ImgType = TGA_Mono;
else if ( pm_keymatch( argv[argn], "-rgb", 2 ) )
tgaHeader.ImgType = TGA_RGB;
else if ( pm_keymatch( argv[argn], "-norle", 2 ) )
rle_flag = 0;
else
pm_usage( usage );
++argn;
}
if ( argn != argc )
{
/* Open the input file. */
ifp = pm_openr( argv[argn] );
/* If output filename not specified, use input filename as default. */
if ( out_name[0] == '\0' )
{
(void) strcpy( out_name, argv[argn] );
cp = index( out_name, '.' );
if ( cp != 0 )
*cp = '\0'; /* remove extension */
if ( strcmp( out_name, "-" ) == 0 )
(void) strcpy( out_name, "noname" );
}
++argn;
}
else
{
/* No input file specified. */
ifp = stdin;
if ( out_name[0] == '\0' )
(void) strcpy( out_name, "noname" );
}
if ( argn != argc )
pm_usage( usage );
/* Read in the ppm file. */
ppm_readppminit( ifp, &cols, &rows, &maxval, &format);
pixels = ppm_allocarray( cols, rows );
for ( row = 0; row < rows; ++row )
ppm_readppmrow( ifp, pixels[row], cols, maxval, format );
pm_close( ifp );
/* Figure out the colormap. */
switch ( PPM_FORMAT_TYPE( format ) )
{
case PPM_TYPE:
if ( tgaHeader.ImgType == TGA_Mono )
pm_error( "input is not a graymap, filter through ppmtopgm first" );
if ( tgaHeader.ImgType == TGA_Null || tgaHeader.ImgType == TGA_Map )
{
pm_message( "computing colormap..." );
chv = ppm_computecolorhist(
pixels, cols, rows, MAXCOLORS, &ncolors );
if ( chv == (colorhist_vector) 0 )
{
if ( tgaHeader.ImgType == TGA_Map )
pm_error(
"too many colors - try doing a 'ppmquant %d'",
MAXCOLORS );
else
tgaHeader.ImgType = TGA_RGB;
}
else
{
pm_message( "%d colors found", ncolors );
if ( tgaHeader.ImgType == TGA_Null )
tgaHeader.ImgType = TGA_Map;
}
}
break;
case PGM_TYPE:
case PBM_TYPE:
if ( tgaHeader.ImgType == TGA_Null )
tgaHeader.ImgType = TGA_Mono;
else if ( tgaHeader.ImgType == TGA_Map )
{
pm_message( "computing colormap..." );
chv = ppm_computecolorhist(
pixels, cols, rows, MAXCOLORS, &ncolors );
if ( chv == (colorhist_vector) 0 )
pm_error( "can't happen" );
pm_message( "%d colors found", ncolors );
}
break;
default:
pm_error( "can't happen" );
}
if ( rle_flag )
{
switch ( tgaHeader.ImgType )
{
case TGA_Mono:
tgaHeader.ImgType = TGA_RLEMono;
break;
case TGA_Map:
tgaHeader.ImgType = TGA_RLEMap;
break;
case TGA_RGB:
tgaHeader.ImgType = TGA_RLERGB;
break;
default:
pm_error( "can't happen" );
}
runlength = (int*) pm_allocrow( cols, sizeof(int) );
}
tgaHeader.IDLength = 0;
tgaHeader.Index_lo = 0;
tgaHeader.Index_hi = 0;
if ( tgaHeader.ImgType == TGA_Map || tgaHeader.ImgType == TGA_RLEMap )
{
/* Make a hash table for fast color lookup. */
cht = ppm_colorhisttocolorhash( chv, ncolors );
tgaHeader.CoMapType = 1;
tgaHeader.Length_lo = ncolors % 256;
tgaHeader.Length_hi = ncolors / 256;
tgaHeader.CoSize = 24;
}
else
{
tgaHeader.CoMapType = 0;
tgaHeader.Length_lo = 0;
tgaHeader.Length_hi = 0;
tgaHeader.CoSize = 0;
}
if ( tgaHeader.ImgType == TGA_RGB || tgaHeader.ImgType == TGA_RLERGB )
tgaHeader.PixelSize = 24;
else
tgaHeader.PixelSize = 8;
tgaHeader.X_org_lo = tgaHeader.X_org_hi = 0;
tgaHeader.Y_org_lo = tgaHeader.Y_org_hi = 0;
tgaHeader.Width_lo = cols % 256;
tgaHeader.Width_hi = cols / 256;
tgaHeader.Height_lo = rows % 256;
tgaHeader.Height_hi = rows / 256;
tgaHeader.AttBits = 0;
tgaHeader.Rsrvd = 0;
tgaHeader.IntrLve = 0;
tgaHeader.OrgBit = 0;
/* Write out the Targa header. */
writetga( &tgaHeader, (char*) 0 );
if ( tgaHeader.ImgType == TGA_Map || tgaHeader.ImgType == TGA_RLEMap )
{
/* Write out the Targa colormap. */
for ( i = 0; i < ncolors; ++i )
put_map_entry( &chv[i].color, tgaHeader.CoSize, maxval );
}
/* Write out the pixels */
for ( row = 0; row < rows; ++row )
{
realrow = row;
if ( tgaHeader.OrgBit == 0 )
realrow = rows - realrow - 1;
if ( rle_flag )
{
compute_runlengths( cols, pixels[realrow], runlength );
for ( col = 0; col < cols; )
{
if ( runlength[col] > 0 )
{
putchar( 0x80 + runlength[col] - 1 );
put_pixel(
&(pixels[realrow][col]),
tgaHeader.ImgType, maxval, cht );
col += runlength[col];
}
else if ( runlength[col] < 0 )
{
putchar( -runlength[col] - 1 );
for ( i = 0; i < -runlength[col]; ++i )
put_pixel(
&(pixels[realrow][col + i]),
tgaHeader.ImgType, maxval, cht );
col += -runlength[col];
}
else
pm_error( "can't happen" );
}
}
else
{
for ( col = 0, pP = pixels[realrow]; col < cols; ++col, ++pP )
put_pixel( pP, tgaHeader.ImgType, maxval, cht );
}
}
exit( 0 );
}
static void
writetga( tgaP, id )
struct ImageHeader* tgaP;
char* id;
{
unsigned char flags;
putchar( tgaP->IDLength );
putchar( tgaP->CoMapType );
putchar( tgaP->ImgType );
putchar( tgaP->Index_lo );
putchar( tgaP->Index_hi );
putchar( tgaP->Length_lo );
putchar( tgaP->Length_hi );
putchar( tgaP->CoSize );
putchar( tgaP->X_org_lo );
putchar( tgaP->X_org_hi );
putchar( tgaP->Y_org_lo );
putchar( tgaP->Y_org_hi );
putchar( tgaP->Width_lo );
putchar( tgaP->Width_hi );
putchar( tgaP->Height_lo );
putchar( tgaP->Height_hi );
putchar( tgaP->PixelSize );
flags = ( tgaP->AttBits & 0xf ) | ( ( tgaP->Rsrvd & 0x1 ) << 4 ) |
( ( tgaP->OrgBit & 0x1 ) << 5 ) | ( ( tgaP->OrgBit & 0x3 ) << 6 );
putchar( flags );
if ( tgaP->IDLength )
fwrite( id, 1, (int) tgaP->IDLength, stdout );
}
#if __STDC__
static void
put_map_entry( pixel* valueP, int size, pixval maxval )
#else /*__STDC__*/
static void
put_map_entry( valueP, size, maxval )
pixel* valueP;
int size;
pixval maxval;
#endif /*__STDC__*/
{
int j;
pixel p;
switch ( size )
{
case 8: /* Grey scale. */
put_mono( valueP, maxval );
break;
case 16: /* 5 bits each of red green and blue. */
case 15: /* Watch for byte order. */
PPM_DEPTH( p, *valueP, maxval, 31 );
j = (int) PPM_GETB( p ) | ( (int) PPM_GETG( p ) << 5 ) |
( (int) PPM_GETR( p ) << 10 );
putchar( j % 256 );
putchar( j / 256 );
break;
case 32:
case 24: /* 8 bits each of blue green and red. */
put_rgb( valueP, maxval );
break;
default:
pm_error( "unknown colormap pixel size (#2) - %d", size );
}
}
static void
compute_runlengths( cols, pixelrow, runlength )
int cols;
pixel* pixelrow;
int* runlength;
{
int col, start;
/* Initialize all run lengths to 0. (This is just an error check.) */
for ( col = 0; col < cols; ++col )
runlength[col] = 0;
/* Find runs of identical pixels. */
for ( col = 0; col < cols; )
{
start = col;
do {
++col;
}
while ( col < cols &&
col - start < 128 &&
PPM_EQUAL( pixelrow[col], pixelrow[start] ) );
runlength[start] = col - start;
}
/* Now look for runs of length-1 runs, and turn them into negative runs. */
for ( col = 0; col < cols; )
{
if ( runlength[col] == 1 )
{
start = col;
while ( col < cols &&
col - start < 128 &&
runlength[col] == 1 )
{
runlength[col] = 0;
++col;
}
runlength[start] = - ( col - start );
}
else
col += runlength[col];
}
}
#if __STDC__
static void
put_pixel( pixel* pP, int imgtype, pixval maxval, colorhash_table cht )
#else /*__STDC__*/
static void
put_pixel( pP, imgtype, maxval, cht )
pixel* pP;
int imgtype;
pixval maxval;
colorhash_table cht;
#endif /*__STDC__*/
{
switch ( imgtype )
{
case TGA_Mono:
case TGA_RLEMono:
put_mono( pP, maxval );
break;
case TGA_Map:
case TGA_RLEMap:
put_map( pP, cht );
break;
case TGA_RGB:
case TGA_RLERGB:
put_rgb( pP, maxval );
break;
default:
pm_error( "can't happen" );
}
}
#if __STDC__
static void
put_mono( pixel* pP, pixval maxval )
#else /*__STDC__*/
static void
put_mono( pP, maxval )
pixel* pP;
pixval maxval;
#endif /*__STDC__*/
{
PPM_DEPTH( *pP, *pP, maxval, (pixval) 255 );
putchar( PPM_GETR( *pP ) );
}
static void
put_map( pP, cht )
pixel* pP;
colorhash_table cht;
{
putchar( ppm_lookupcolor( cht, pP ) );
}
#if __STDC__
static void
put_rgb( pixel* pP, pixval maxval )
#else /*__STDC__*/
static void
put_rgb( pP, maxval )
pixel* pP;
pixval maxval;
#endif /*__STDC__*/
{
PPM_DEPTH( *pP, *pP, maxval, (pixval) 255 );
putchar( PPM_GETB( *pP ) );
putchar( PPM_GETG( *pP ) );
putchar( PPM_GETR( *pP ) );
}