[comp.graphics] Targa to sun

870646c@aucs.UUCP (Barry Comer) (02/18/89)

Has anyone have information on a prg. that will convert images from a 
Targa frame buffer to images that can be displayed on a Sun 3\60.

later
Barry Comer

macphed@dvinci.USask.CA (Ian MacPhedran) (02/22/89)

From article <1581@aucs.UUCP>, by 870646c@aucs.UUCP (Barry Comer):
> Has anyone have information on a prg. that will convert images from a 
> Targa frame buffer to images that can be displayed on a Sun 3\60.
> 
> later
> Barry Comer
As I recall a message similar to this not too long ago, I am posting this
rather than mailing it.

Enclosed is the source code for a .tga (Targa) file to SUN 8-bit rasterfile
conversion program. I must warn you however, that this code is not
pretty. I have just finished it and am sending it off, as there seems to
be a demand for it.

This supports most of the variants of the TrueVision's image file types,
(at least, those that I know) but now all are supported. (For example,
compressed files.) As well, the colour version only does the old 3-3-2
colour fake (3 bits of red & green, 2 bits of blue), and not a more
intellegent adaptive colour mapping (the approaches I played with are too
slow to be usefull) nor dithering.


If you do use this code, please send me an e-mail message. (I'd like to get
feedback on what you think of the program, find others out there using
TrueVision graphics, and ensure our posting program is working - I have
my doubts about the latter.)

Enjoy.
Ian.

+------------------------------------+-----------------------------------+
| Ian MacPhedran                     | USEnet macphed@dvinci.UUCP        |
| Engineering Applications           | BITNET MacPhedran@Sask            |
| Department of Computing Services   | InterNet macphedran@sask.USask.CA |
| 2B13 Engineering Bldg.             | Phone  (306) 966-4832             |
| University of Saskatchewan, Saskatoon, Saskatchewan, Canada S7N 0W0    |
+------------------------------------------------------------------------+
---cut here---------------
#! /bin/sh
#
# This is a home built shar file. Just run it through /bin/sh, and
# it will create the following files:
#
# README       (Brief description)
# TGAFile.h    (a required header file)
# tga2rast.c   (actual c source for program)
# tga2rast.l   (a man page for this program)
#
# Enjoy
#
if test -f README
then
echo "Will not overwrite existing README file."
else
echo - x README
cat - > README << XXX_EOF_XXX
This is a program to translate images from the TrueVision Targa and
Vista systems into SUN rasterfiles. This will do two forms of trans-
lation, one for grey scale images, and one for colour images. The
colour translation is done by taking the top three bits of red and
green, and the top two bits of blue.

To make the program, make sure that you have tga2rast.c and TGAFile.h
in your current directory, AND that you have SUN's rasterfile.h file
in /usr/include. Then simply compile:

% cc -o tga2rast tga2rast.c

To use, give the command:

% tga2rast tga_file raster_file

to get the grey level rasterfile, or

% tga2rast -c tga_file raster_file

to get the colour rasterfile.

Complaints, questions, etc. may be addressed to:

macphed@dvinci.USask.CA
macphed@dvinci.UUCP         (..!alberta!dvinci!macphed)
macphedran@sask.USask.CA
macphedran@sask.BITNET
XXX_EOF_XXX
if test 858 -ne `wc -c README | awk '{ print $1 }' `
then
echo "README - size should be 858"
fi
fi
if test -f TGAFile.h
then
echo "Will not overwrite existing TGAFile.h file."
else
echo - x TGAFile.h
cat - > TGAFile.h << XXX_EOF_XXX
/*
 * Header file for Targa file definitions.
 *
 * These definitions will allow a consistant interface to build Targa (.TGA)
 * image files.
 *
 * Created NOV-15-1988 IJMP
 *
 */
 
/* File header definition */

struct ImageHeader {
		unsigned char IDLength;/* Length of Identifier String */
		unsigned char CoMapType;	/* Always 0 */
		unsigned char ImgType;	/* Image Type (2,3,10) */
		unsigned char Index_lo, Index_hi;	/* Index of first colour map entry */
		unsigned char Length_lo, Length_hi;	/* Length of colour map (number of entries) */
		unsigned char CoSize;	/* Length of colour map entry */
		unsigned char X_org_lo, X_org_hi;	/* X Origin of Image */
		unsigned char Y_org_lo, Y_org_hi;	/* Y Origin of Image */
		unsigned char Width_lo, Width_hi;	/* Width of Image */
		unsigned char Height_lo, Height_hi;	/* Height of Image */
		unsigned char PixelSize;		/* Pixel Size (8,16,24) */
		unsigned AttBits : 4;	/* Number of Attribute Bits per pixel */
		unsigned Rsrvd   : 1;	/* Reserved bit */
		unsigned OrgBit  : 1;	/* Origin Bit (0=lower left, 1=upper left) */
		unsigned IntrLve : 2;	/* Interleaving Flag */
		};

typedef char ImageIDField[256];

/* Definitions for Image Types */
#define TGA_RGBType 2
#define TGA_MonoType 3
#define TGA_EnCodeType 10
XXX_EOF_XXX
if test 1263 -ne `wc -c TGAFile.h | awk '{ print $1 }' `
then
echo "TGAFile.h - size should be 1263"
fi
fi
if test -f tga2rast.c
then
echo "Will not overwrite existing tga2rast.c file."
else
echo - x tga2rast.c
cat - > tga2rast.c << XXX_EOF_XXX
/*
 * tga2rast.c
 * Ian MacPhedran
 * Engineering Computer Centre
 * University of Saskatchewan
 * Saskatoon Saskatchewan Canada
 *
 * macphed@dvinci.USask.CA, macphedran@sask.USask.CA
 *
 * This program will read in a .TGA file and create a SUN raster file.
 *
 * Version 1.0 - first released for public consumption, 21 Feb, 1989
 *
 */

#include <stdio.h>
#include <rasterfile.h>
#include "TGAFile.h"

#define MAXARGS 4
#define BUFSIZE 65536
#define MAXCOLOURS 16384

/* Define flags for mode - these indicate special conditions */
#define GREYSC 0
#define COLOUR 1
#define MAPPED 2
#define RLENCD 4
#define INTERL 8
#define FOURWY 16

unsigned char ColourMap[MAXCOLOURS];
int RLE_count=0,RLE_flag=0;
void usage();

/* The following should be replaced by macros */

/*
 * Calculate the luminance of an eight bit triplet of Red Green Blue values.
 *
 */
#define lumin(r,g,b) \
 (unsigned char)(0.299 * (float)r + 0.587 * (float)g + 0.114 * (float)b + 0.5)

/*
 * Calculate an eight bit colour value from a triplet of Red Green Blue values.
 *
 */
#define col8(r,g,b) \
 (unsigned char)((r & 0xE0) + ((g & 0xE0) >> 3) + ((b & 0xC0) >> 6))

main(argc,argv)
int argc;
char *argv[];
{
/* Define Identifiers */
struct rasterfile	rst_file;
struct ImageHeader	tga_head;
int			i, j, l, FileFlag=0, mode=GREYSC;
unsigned int		temp1, temp2;
unsigned char		colmap[256],buf[BUFSIZE];
unsigned long		k, baseline;

	/* Parse Command Line */
	if ( (argc == 0) || (argc > MAXARGS) )
	{
		usage();
		exit(1);
	}

	for (i=1; i < argc; i++)
	{
		if (argv[i][0] == '-')
		{
			switch(argv[i][1])
			{
				case 'c': mode = COLOUR; break;
				case 'g': mode = GREYSC; break;
				default : usage();
			}
		}
		/* Filename ? */
		else
		switch(FileFlag)
		{
			case 0:	/* First filename - input file */
				FileFlag = 1;
				if ( freopen(argv[i],"r",stdin) == NULL)
				{
				fprintf(stderr,"Can't open input file %s\n",
					 argv[i]);
					exit(1);
				}
				break;
			case 1: /* Second filename - output file */
				FileFlag = 2;
				if ( freopen(argv[i],"w",stdout) == NULL)
				{
					fprintf(stderr,"Can't open output file %s\n",
					 argv[i]);
					exit(1);
				}
				break;
			default:
				fprintf(stderr,"Too many filenames\n");
				usage();
				exit(1);
		}
	}
	if (FileFlag != 2)
	{
		fprintf(stderr,"Requires two filenames.\n");
		usage();
		exit(1);
	}

	/* Input the Targa file header */
	readtga(&tga_head,&rst_file);

	/* Write out rasterfile header */
	fwrite(&rst_file,sizeof(struct rasterfile),1,stdout);

	/* Create and write Colour Map */
	switch (mode)
	{
		case COLOUR :
			/* write red component */
			for (i=0; i<256; i++) colmap[i] = i & 0xe0;
			fwrite(colmap, sizeof(colmap), 1, stdout);
			/* write green */
			for (i=0; i<256; i++) colmap[i] = (i & 0x1c) << 3;
			fwrite(colmap, sizeof(colmap), 1, stdout);
			/* write blue */
			for (i=0; i<256; i++) colmap[i] = (i & 0x03) << 6;
			fwrite(colmap, sizeof(colmap), 1, stdout);
			break;
			
		case GREYSC :
			for (i= 0; i < 256; i++) colmap[i]= i;
			fwrite(colmap, sizeof(colmap), 1, stdout);
			fwrite(colmap, sizeof(colmap), 1, stdout);
			fwrite(colmap, sizeof(colmap), 1, stdout);
			break;
	}

	/* If required, read the colour map information */
        if (tga_head.CoMapType != 0)
        {
		temp1 = tga_head.Index_lo + tga_head.Index_hi * 256;
		temp2 = tga_head.Length_lo + tga_head.Length_hi * 256;
		if ((temp1+temp2+1) >= MAXCOLOURS)
		{
			fprintf(stderr,"Too many colours %d\n",(temp1+temp2+1));
			exit(1);
		}
		for (i=temp1; i<(temp1+temp2); i++)
			get_map_entry(&ColourMap[i],tga_head.CoSize,mode);
		if ((tga_head.ImgType !=2) && (tga_head.ImgType != 3) &&
		    (tga_head.ImgType !=10))
			mode = mode | MAPPED;
	}

	/* Check Run Length Encoding */
	if ((tga_head.ImgType == 9) || (tga_head.ImgType == 10))
		mode = mode | RLENCD;

	/* Check for interlacing of the Targa file */
	switch (tga_head.IntrLve)
	{
		case 2: /* Four way interlace */
			mode = mode | FOURWY;
		case 1: /* Two way interlace */
			mode = mode | INTERL;
		case 0: /* No interlace */
			break;
		default: /* Reserved - we'll let it pass */
			break;
	}

	/* Read the Targa file body and convert to rasterfile format */
	baseline = (rst_file.ras_height - 1) * rst_file.ras_width
		+ sizeof(struct rasterfile) + rst_file.ras_maplength;
	for (i=0; i<rst_file.ras_height; i++)
	{
		for (j=0; j<rst_file.ras_width; j++)
			get_pixel(&buf[j],tga_head.PixelSize,mode);
		/* No interlace */
		if ((mode & INTERL) == 0)
		{
			j = i;
		}
		/* Two way interlace */
		else if ((mode & FOURWY) != 0)
		{
			if (2*i < rst_file.ras_height)
				j = 2*i;
			else
			{
				j = i - rst_file.ras_height/2;
				j = 2*j + 1;
			}
		}
		/* Four way interlace */
		else
		{
			if (4*i < rst_file.ras_height)
				j = 4*i;
			else if (2*i < rst_file.ras_height)
			{
				j = i - rst_file.ras_height/4;
				j = 4*j + 1;
			}
			else if (4*i < 3*rst_file.ras_height)
			{
				j = i - rst_file.ras_height/2;
				j = 4*j + 2;
			}
			else
			{
				j = i - rst_file.ras_height/2 - rst_file.ras_height/4;
				j = 4*j + 3;
			}
		}
		k = baseline - (j * rst_file.ras_width);
		fseek(stdout,k,0);
		fwrite(buf,rst_file.ras_width,1,stdout);
	}
	fclose(stdout);fclose(stdin);exit(0);
}

void usage()
{
	fprintf(stderr,"Usage: tga2rast [-c | -g] infile outfile\n");
	fprintf(stderr,"\n-c option for colour output,");
	fprintf(stderr,"\n-g option for grey scale output (default),");
	fprintf(stderr,"\ninfile is Targa (.tga) file,");
	fprintf(stderr,"\noutfile is rasterfile\n");
}

/*
 * Routine to read Targa file header and create rasterfile header.
 * Targa file is read from stdin.
 *
 */

readtga(tga,rst)
struct ImageHeader *tga;
struct rasterfile *rst;
{
unsigned int i,temp1,temp2;
char ID_Field[256];

	if ((i = fread(tga,1,18,stdin)) != 18)
	{
		fprintf(stderr,"Read only %d bytes in header\n",i);
		exit(1);
	}
	/* Create output file header */
	rst->ras_magic = RAS_MAGIC;
	temp1 = tga->Height_lo; temp2 = tga->Height_hi;
	rst->ras_height = temp1 + temp2 * 256;
	temp1 = tga->Width_lo; temp2 = tga->Width_hi;
	rst->ras_width = temp1 + temp2 * 256;
	rst->ras_depth = 8;
	rst->ras_length = rst->ras_height * rst->ras_width;
	rst->ras_type = RT_STANDARD;
	rst->ras_maptype = RMT_EQUAL_RGB;
	rst->ras_maplength = 256*3;

	if (tga->IDLength != 0)
		fread(ID_Field,1, tga->IDLength,stdin);
}


get_map_entry(Value,Size,mode)
unsigned char     *Value;
int     Size,mode;
{
unsigned int j,k,l,m;
unsigned char i,r,g,b;

        /* read appropriate number of bytes, break into rgb & put in map */
        switch (Size)
        {
	        case 8: /* Grey Scale already, read and triplicate */
	                fread(&i,1,1,stdin);
			r = i; g = i; b = i;
	                break;

	        case 16: /* 5 bits each of red green and blue */
	        case 15: /* Watch for byte order */
	                fread(&j,1,1,stdin);
	                fread(&k,1,1,stdin);
	                l = j + k*256;
	                r = ((l >> 10) & 31) << 3;
	                g = ((l >>  5) & 31) << 3;
	                b = (l & 31) << 3;
	                break;

	        case 32: /* Read alpha byte & throw away */
	                fread(&i,1,1,stdin);
	        case 24: /* Eight bits each of red green and blue */
	                fread(&i,1,1,stdin); r = i;
	                fread(&i,1,1,stdin); g = i;
	                fread(&i,1,1,stdin); b = i;
	                break;

	        default:
	                fprintf(stderr,"Unknown Pixel Size\n"); exit(1);
        }
	if (mode == COLOUR)
		*Value = col8(r,g,b);
	else
		*Value = lumin(r,g,b);
}

get_pixel(dest,Size,mode)
unsigned char *dest;
int Size,mode;
{
	static unsigned char Red, Grn, Blu;
	unsigned char i,j,k;
	static unsigned int l;

	/* Check if run length encoded. */
	if ((mode & RLENCD) != 0)
	{
		if (RLE_count == 0) /* Have to restart run */
		{
			fread(&i,1,1,stdin);
			RLE_flag = (i & 0x80) >> 7;
			if (RLE_flag == 0)
			{ /* Stream of unencoded pixels */
				RLE_count = i + 1;
			}
			else
			{ /* Single pixel replicated */
				RLE_count = i - 127;
			}
			RLE_count--; /* Decrement count & get pixel */
		}
		else
		{ /* Have already read count & (at least) first pixel */
			RLE_count--;
			if (RLE_flag != 0)
			{ /* Replicated pixels */
				goto PixEncode;
			}
		}
	}
	/* Read appropriate number of bytes, break into RGB */
	switch(Size)
	{
	case 8: /* Grey Scale - read a byte and triplicate */
		fread(&i,1,1,stdin);
		Red = i; Grn = i; Blu = i; l = i;
		break;

	case 16: /* Five bits each of red green and blue */
	case 15: /* Watch byte order */
		fread(&j,1,1,stdin);
		fread(&k,1,1,stdin);
		l = j + k*256;
		Red = ((k & 0x7C) << 1);
		Grn = ((k & 0x03) << 6) + ((j & 0xE0) >> 2);
		Blu = ((j & 0x1F) << 3);
		break;

	case 32: /* Read alpha byte & throw away */
		fread(&i,1,1,stdin);
	case 24: /* Eight bits each of red green and blue */
		fread(&i,1,1,stdin); Red = i;
		fread(&i,1,1,stdin); Grn = i;
		fread(&i,1,1,stdin); Blu = i;
		l = 0;
		break;

	default:
		fprintf(stderr,"Unknown Pixel Size\n"); exit(1);
	}

PixEncode:
	if ((mode & MAPPED) == MAPPED)
	{
		*dest = ColourMap[l];
	}
	else
	if ((mode & COLOUR) == COLOUR)
	{
		*dest = col8(Red,Grn,Blu);
	}
	else
	{
		*dest = lumin(Red,Grn,Blu);
	}
}
XXX_EOF_XXX
if test 9192 -ne `wc -c tga2rast.c | awk '{ print $1 }' `
then
echo "tga2rast.c - size should be 9192"
fi
fi
if test -f tga2rast.l
then
echo "Will not overwrite existing tga2rast.l file."
else
echo - x tga2rast.l
cat - > tga2rast.l << XXX_EOF_XXX
.TH TGA2RAST 1 "21 February 1989" "Ian MacPhedran"
.ds PS P\s-2OST\s+2S\s-2CRIPT\s+2
.SH NAME
tga2rast \- convert TrueVision .tga (Targa) file to SUN rasterfile
.SH "SYNOPSIS"
.B tga2rast
[
.BI \-g
]
.BI infile\ outfile
.br
.B tga2rast \-c infile\ outfile

.SH "DESCRIPTION"
.I Tga2rast
accepts a TrueVision .tga (or Targa) file as input, and creates a
SUN 8-bit (256 colour) rasterfile as output. Both the
.I infile
and
.I outfile
must be specified.
.sp
The possible options are:
.TP
.BI \-g
produces a grey scale (or luminance) image. This is a 256 grey shade image.
If no option is specified, this is the default.
.TP
.BI \-c
produces a "colour" image. The colour is actually composed of the most
significant 3 bits of red, 3 bits of green, and 2 bits of blue in the
.I infile.
This option can lead to problems with images which are originally grey
scale, or of low intensity.
.SH "FILES"
.TP 2.2i
/usr/include/rasterfile.h
SUN rasterfile definitions
.TP 2.2i
./TGAFile.h
TrueVision Targa file definitions
.SH "SEE ALSO"
raster8to1(1), rasterfile(5).
.SH "DIAGNOSTICS"
Should be self explanatory.
.SH AUTHOR
Ian J. MacPhedran,
.br
Engineering Computer Centre,
.br
University of Saskatchewan,
.br
Saskatoon, Saskatchewan, CANADA.
.br
S7N 0W0

.br
(306) 966-4832
.br
macphed@dvinci.USask.CA, macphed@dvinci.UUCP, macphedran@sask.USask.CA,
macphedran@sask.BITNET
.SH "NOTES"
TrueVision and Targa are trademarks, as is SUN.
.br
This software is placed in the public domain. There are no restrictions
on its use, but don't blame the author if it doesn't work for you.
(However, please mention him if you adapt the code to something else,
and inform him of any improvements that can be made.)
.SH "BUGS"
Could do better colour mapping or dithering. Doesn't cover all TrueVision
file types. Watch out for unusual images sizes, especially those with odd
(as opposed to even) numbers of rows and/or columns.
XXX_EOF_XXX
if test 1902 -ne `wc -c tga2rast.l | awk '{ print $1 }' `
then
echo "tga2rast.l - size should be 1902"
fi
fi
exit 0
--------end file----cut again---------