home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TopWare 18: Liquid
/
Image.iso
/
liquid
/
top1089
/
rdsgen.c
< prev
next >
Wrap
Text File
|
1993-12-17
|
65KB
|
2,650 lines
/* */
/* RDSGEN.C - Random-Dot Stereogram Generator */
/* */
/* Version 1.1B */
/* */
/* Written by: Fred Feucht */
/* */
/* */
/* This program will take a type 2 TARGA or GIF file as input and */
/* generate a type 3 TARGA or GIF output file as an RDS. */
/* */
/* The original code comes from RDS.C by Alexander R. Enzmann, which I */
/* found to be too inflexible. The RDS algorithm is a modification of */
/* the routine documented by Paul McMahon in "The Emporors New Clothes". */
/* With the additions of GIF encoding and decoding routines from TGA2GIF */
/* and POVRay respectively (authors are mentioned below). */
/* */
/* My thanks to all the previous authors whose code fragments appear */
/* herein. I have given credit wherever possible to original authors. */
/* To those not specifically mentioned, I am grateful as well. */
/* */
/* Permission is given by the author to freely redistribute and include */
/* this code in any program as long as this credit is given where due. */
/* */
/* GIF and 'Graphics Interchange Format' are trademarks (tm) of */
/* Compuserve, Incorporated, an H&R Block Company. */
/* */
/***************************************************************************/
/* */
/* Revisions for release 1.1 */
/* */
/* */
/* Additional RDS algorithms /a switch */
/* */
/* Random color background /c switch */
/* */
/* GIF background map /m switch */
/* */
/* Depth of field control /f switch */
/* */
/* Printer support for EPSON LQ, LASER JET, and POSTSCRIPT (incomplete) */
/* */
/* */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>
#include <ctype.h>
#include <graphics.h>
#include "rdsgen.h"
/* */
/* Global variables */
/* */
static int stripc, density, direction, outfile, display, field;
static int color_back, seed, algorithm, adapt, index_points;
static int stripw, intype, point_max, map_file, scale;
static long limit, zmax, zmin, newval, oldval, num, den;
static unsigned int xres, yres;
static unsigned int * depths;
static unsigned char * odata;
static int Width, Height;
static int curx, cury;
static long CountDown;
static int Pass = 0;
static int Interlace;
static FILE * ofile;
static char * oname;
static char * printer;
static unsigned char * printx;
static unsigned char ** printy;
static int * same;
static int sep;
static int left, right, sl, sr;
/* */
/* input file stuff */
/* */
static FILE * ifile; /* input file handle */
static char * iname; /* input file name */
static unsigned char * iemit_index;
static unsigned char * icmap;
static unsigned int ftype, icmlen, icmsize, ipsize, idlen;
static int icode_size, iout_value, iold_code, ibad_code_count;
LOCAL WORD icurr_size; /* The current code size */
LOCAL WORD iclear; /* Value for a clear code */
LOCAL WORD iending; /* Value for a ending code */
LOCAL WORD inew_codes; /* First available code */
LOCAL WORD itop_slot; /* Highest code for current size */
LOCAL WORD islot; /* Last read code */
LOCAL WORD ibyte_count = 0; /* # bytes left in block */
LOCAL WORD ibit_count = 0; /* # bits left in current byte */
LOCAL UTINY ibyte_buff[257]; /* Current block */
LOCAL UTINY * ibyte_ptr; /* Pointer to next byte in block */
LOCAL UTINY ibyte; /* current input byte */
LOCAL UTINY * idstack; /* Stack for storing pixels */
LOCAL UTINY * isuffix; /* Suffix table */
LOCAL UWORD * iprefix; /* Prefix linked list */
/* */
/* background file stuff */
/* */
static FILE * bfile; /* input file handle */
static char * bname; /* input file name */
static unsigned char * bemit_index;
static int bcode_size, bout_value, bold_code, bbad_code_count;
static unsigned char * bcmap;
static unsigned int bxres, byres, bcmlen, bcmsize;
LOCAL WORD bcurr_size; /* The current code size */
LOCAL WORD bclear; /* Value for a clear code */
LOCAL WORD bending; /* Value for a ending code */
LOCAL WORD bnew_codes; /* First available code */
LOCAL WORD btop_slot; /* Highest code for current size */
LOCAL WORD bslot; /* Last read code */
LOCAL WORD bbyte_count = 0; /* # bytes left in block */
LOCAL WORD bbit_count = 0; /* # bits left in current byte */
LOCAL UTINY bbyte_buff[257]; /* Current block */
LOCAL UTINY * bbyte_ptr; /* Pointer to next byte in block */
LOCAL UTINY bbyte; /* current input byte */
LOCAL UTINY * bdstack; /* Stack for storing pixels */
LOCAL UTINY * bsuffix; /* Suffix table */
LOCAL UWORD * bprefix; /* Prefix linked list */
/* */
/* output file stuff */
/* */
static unsigned char idbuf[256];
static int n_bits; /* number of bits/code */
static int maxbits = BITS; /* user settable max # bits/code */
static code_int maxcode; /* maximum code, given n_bits */
static code_int maxmaxcode = (code_int)1 << BITS; /* should NEVER generate this code */
static count_int htab [HSIZE];
static unsigned short codetab [HSIZE];
static code_int free_ent = 0; /* first unused entry */
static int exit_stat = 0;
static int clear_flg = 0;
static int offset;
static long int in_count = 1; /* length of input */
static long int out_count = 0; /* # of codes output (for debugging) */
static int g_init_bits;
static FILE *g_outfile;
static int ClearCode;
static int EOFCode;
static code_int hsize = HSIZE; /* for dynamic table sizing */
static count_int fsize;
static unsigned long cur_accum = 0;
static int cur_bits = 0;
LOCAL ULONG code_mask[17] = {
0,
0x0001, 0x0003,
0x0007, 0x000F,
0x001F, 0x003F,
0x007F, 0x00FF,
0x01FF, 0x03FF,
0x07FF, 0x0FFF,
0x1FFF, 0x3FFF,
0x7FFF, 0xFFFF
};
static int red[256] = { 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F, 0x7F, 0x1F, 0x1F, 0x1F, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF };
static int green[256] = { 0x00, 0x00, 0x7F, 0x7F, 0x00, 0x00, 0x1F, 0x7F, 0x1F, 0x1F, 0xFF, 0xFF, 0x1F, 0x1F, 0xFF, 0xFF };
static int blue[256] = { 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x1F, 0xFF, 0x1F, 0xFF, 0x1F, 0xFF, 0x1F, 0xFF };
const char GIFstr[] = "GIF87a";
/* */
/* Main processing routine */
/* */
void main(argc, argv)
int argc;
char **argv;
{
int i, j;
int driver, mode, errcode;
unsigned char * t;
stripc = 8; /* strip length = 1/8 of screen width */
density = 50; /* density 50 out of 100 pixels black */
direction = 0; /* normal picture orientation */
outfile = 0; /* output file is GIF format */
display = 0; /* do not display output while working */
seed = 1; /* random number seed */
adapt = 0; /* no background substitution */
index_points = 0; /* no indexing triangles in RDS output */
point_max = 0; /* size of index points */
algorithm = 2; /* use improved RDS algorithm */
color_back = 0; /* use black and white palette */
map_file = 0; /* no background map file */
field = 2; /* field is 1/2 the distance to image */
printer = NULL; /* no list device */
newval = 0xFFFF; /* adaptive background replacement */
if (argc < 3)
{
showparms();
exit(0);
}
iname = argv[1];
oname = argv[2];
for(i=3; i<argc; i++)
{
if(argv[i][0] == '+' || argv[i][0] == '-' || argv[i][0] == '/')
{
switch (argv[i][1])
{
case '?': showparms();
break;
case 'a':
case 'A': if(argv[i][2] == '\0') error("Missing algorithm number\n");
algorithm = atoi(argv[i]+2);
if(algorithm < 1 || algorithm > 3) error("Algorithm number, %i, is out of range\n", algorithm);
break;
case 'b':
case 'B': if(argv[i][2] == '\0') error("Missing adaptive background substitution value\n");
adapt = atoi(argv[i]+2);
if(adapt < 1 || adapt > 64) error("Adaptive background offset, %i, is out of range\n", adapt);
break;
case 'c':
case 'C': color_back = 1;
break;
case 'd':
case 'D': if(argv[i][2] == '\0') error("Missing density value\n");
density = atoi(argv[i]+2);
if(density < 0 || density > 100) error("Density value, %i, is out of range\n", density);
break;
case 'f':
case 'F': if(argv[i][2] == '\0') error("Missing depth of field value\n");
field = atoi(argv[i]+2);
if(field < 1 || field > 16) error("Depth of field value, %i, is out of range\n", field);
break;
case 'i':
case 'I': index_points = 1;
break;
case 'm':
case 'M': if(argv[i][2] == '\0') error("Missing map file name\n");
bname = &argv[i][2];
map_file = 1;
break;
case 'n':
case 'N': direction = 1;
break;
case 'p':
case 'P': if(argv[i][2] == '\0') error("Missing printer device name\n");
printer = &argv[i][2];
break;
case 'r':
case 'R': if(argv[i][2] == '\0') error("Missing random seed value\n");
seed = atoi(argv[i]+2);
break;
case 's':
case 'S': if(argv[i][2] == '\0') error("Missing strip count value\n");
stripc = atoi(argv[i]+2);
break;
case 't':
case 'T': outfile = 1;
break;
case 'v':
case 'V': display = 1;
break;
default: error("Unknown option: %s\n", argv[i]);
}
}
else error("Invalid switch\n");
}
if(map_file)
{
if(display) error("Video display is not available with bit-mapped background files\n");
if(outfile) error("Output format must be GIF\n");
if(color_back) error("Random color and bit-mapped color are mutually exclusive\n");
}
oldval = (direction) ? 1 : 0xFFFF;
ifile = fopen(iname, "rb");
if (ifile == (FILE *)NULL) error("Cannot open input file \"%s\".", iname);
read_header_data(&xres, &yres);
printf("xres: %d, yres: %d\n", xres, yres);
printf("zmin: %u, zmax: %u\n", (unsigned) zmin, (unsigned) zmax);
if((stripc < 1) || (stripc > xres)) error("Strip count value, %i, is out of range\n", stripc);
stripw = xres / stripc;
if(map_file)
{
bfile = fopen(bname, "rb");
if (bfile == (FILE *)NULL) error("Cannot open background map file \"%s\".", bname);
read_background_header(&bxres, &byres);
if(xres != bxres || yres != byres) error("Background map file resolution (%i x %i) does not match input resolution\n", bxres, byres);
if(byres < stripw) error("Background map file resolution (%i x %i) is less than strip width, %i\n", bxres, byres, stripw);
}
point_max = yres >> 6;
if(adapt)
{
newval = zmin - ((zmax - zmin) / adapt);
zmin = newval;
}
limit = (long) density * RAND_MAX / 100;
if((seed < 1) || (seed > RAND_MAX)) error("Random number seed value, %i, is out of range\n", seed);
srand(seed);
if ((depths = (unsigned int *)malloc(xres * sizeof(unsigned int))) == NULL) error("Failed to allocate data row array\n");
if ((odata = malloc(xres * sizeof(unsigned char))) == NULL) error("Failed to allocate the output image buffer\n");
if(algorithm == 3)
{
if((same = malloc(xres * sizeof(int))) == NULL) error("Unable to allocate constraint array\n");
stripw = xres >> 3; /* strip width for index points */
}
num = (zmax - zmin) * field + zmin; /* numerator for depth calculation */
den = 2 * (zmax - zmin) * field + zmin; /* denumerator for depth calculation */
scale = xres >> 2; /* scale for depth calculation */
if(printer != NULL)
{
if((printy = (unsigned char **) malloc(yres * sizeof(unsigned char *))) == NULL) error("Unable to allocate print lines array\n");
if(color_back != 0) printf("Monochrome RDS will be generated for printer\n");
color_back = 0;
}
if(outfile == 1)
{
printf("Generating TGA output file\n");
}
else
{
printf("Generating GIF output file\n");
if(!color_back)
{
for(i=0; i<256; i++)
{
red[i] = i;
green[i] = i;
blue[i] = i;
}
}
if(map_file)
{
for(i=0, j=0; i<256; i++)
{
red[i] = bcmap[j++];
green[i] = bcmap[j++];
blue[i] = bcmap[j++];
}
}
}
if(display)
{
switch(xres)
{
case 320: if(yres != 200) error("Unable to display %i by %i image\n", xres, yres);
driver = CGA;
mode = 1;
break;
case 640: if(yres == 480)
{
driver = VGA;
mode = 2;
break;
}
driver = EGA;
if(yres == 350)
{
mode = 1;
break;
}
if(yres == 200)
{
mode = 0;
break;
}
default: error("Unable to display %i by %i image\n", xres, yres);
}
initgraph(&driver, &mode, 0);
errcode = graphresult();
if(errcode != grOk)
{
printf("%s\n", grapherrormsg(errcode));
exit(0);
}
}
if(outfile == 1)
{
TGAEncode(oname, /* file name */
xres,yres); /* image size */
}
else
{
GIFEncode(oname, /* file name */
xres, yres, /* image size */
0, /* no interlace */
0, /* bkg color */
8, /* bits per pixel */
red, green, blue, /* palette arrays */
get_pix); /* pixel function */
}
if(printer != NULL) printout();
if(display == 0)
{
printf("\n");
}
else
{
beep();
while(!kbhit());
closegraph();
}
if(map_file) fclose(bfile);
fclose(ifile);
}
/* */
/* Generate a line of RDS from a line of depth data (left to right) */
/* */
/* Three RDS algorithms are available */
/* */
/* Algorithm 1: */
/* */
/* First just generate random dots across the line */
/* */
/* Next go through depth data, adjusting pixels according to following */
/* */
/* o = strip width - depth[i] */
/* */
/* pixel[i+o] = pixel[i-o] */
/* */
void gen_rds_line(int width)
{
int d, i, j, n, o, w;
long l, z;
unsigned int k;
long inc, dt;
w = stripw / field; /* limit useable strip by depth of field */
z = zmax - zmin; /* calculate useable portion of strip */
if(algorithm == 1)
{
n = 0; /* initialize left-most pixel */
/* first, just generate background dots */
if(map_file)
{
for(i=0; i<stripw; i++) /* get dots from background map */
{
if((k = bget_map()) == bending) error("Premature EOF in map file, %s\n", bname);
odata[i] = k;
}
for(j=i; j<bxres; j++)
{
if((k = bget_map()) == bending) error("Premature EOF in map file, %s\n", bname);
odata[j] = k; /* fill-in entire line */
}
}
else
{
if(color_back) /* if random color background */
{
for(i=0; i<stripw; i++) odata[i] = ((long) rand() << 4) / RAND_MAX;
}
else /* if back and white background */
{
for(i=0; i<stripw; i++) odata[i] = (rand() < limit) ? 0 : 255;
}
}
for(; i<width; i++)
{
if(!map_file)
{
if(color_back)
{
odata[i] = ((long) rand() << 4) / RAND_MAX;
}
else
{
odata[i] = (rand() < limit) ? 0 : 255;
}
}
l = depths[i] & 0xFFFF; /* extract depth value */
o = (((l - zmin) * w) / z); /* scale to strip width */
d = (i - stripw + o); /* calculate displacement to corresponding pixel */
if(d >= n) /* if from pixel right of last from pixel */
{
odata[i] = odata[d]; /* copy depth adjusted pixel from previous strip */
n = d; /* new left-most pixel */
}
}
}
if(algorithm == 2)
{
n = 0; /* left-most pixel */
/* first just generate random dots */
if(map_file)
{
for(i=0; i<bxres; i++)
{
if((k = bget_map()) == bending) error("Premature EOF in map file, %s\n", bname);
odata[i] = k;
}
}
else
{
if(color_back)
{
for(i=0; i<width; i++) odata[i] = ((long) rand() << 4) / RAND_MAX;
}
else
{
for(i=0; i<width; i++) odata[i] = (rand() < limit) ? 0 : 255;
}
}
/* now go back and adjust for depth */
for(i=0; i<width; i++)
{
l = depths[i] & 0xFFFF; /* extract depth value */
o = (num - l) * scale / (den - l); /* calculate separation */
d = i - (o >> 1); /* left pixel is 1/2 offset back */
if((d > -1) && ((d+o) < width)) /* if both pixels visible */
{
if(d >= n) /* if visible by both eyes */
{
odata[d+o] = odata[d]; /* propagate pixel forward */
n = d; /* new left most pixel */
}
}
}
}
if(algorithm == 3)
{
/* initialize same array */
for(i=0; i<width; i++) same[i] = i;
/* scan line for pixel constraints */
for(i=0; i<width; i++)
{
l = depths[i] & 0xFFFF; /* extract depth value */
sep = (num - l) * scale / (den - l); /* calculate separation length */
left = i - sep / 2; /* left is current - 1/2 separation */
right = sep + left; /* right is left plus separation */
if(left >= 0 && right < width) /* if both pixels on the screen */
{
w = 1; /* assume point is visible */
dt = depths[i] & 0xFFFF - zmin; /* get relative depth value */
inc = (16 * field * z - 8 * dt) / xres; /* depth increase per unit of width */
for(j=1; dt<z; j++) /* while relative depth within limits */
{
dt += inc; /* increment relative depth value */
l = dt + zmin; /* convert to absolute depth value */
if((i-j) >= 0 && depths[i-j] > l) /* if on screen and occluded */
{
w = 0; /* pixel is not visible (constrained) */
break;
}
if((i+j) < width && depths[i+j] > l) /* if on screen and occluded */
{
w = 0; /* pixel is not visible (constrained) */
break;
}
}
if(w) /* if visible */
{
if(same[left] < right) /* if previous constraint is left of new */
{
same[same[left]] = right; /* previous node is constrained to new */
same[left] = right; /* new right-most constraint on this pixel */
}
else
{
same[right] = same[left]; /* right pixel is constrained to further right */
}
}
}
}
for(i=width-1; i>=0; i--) /* scan backwards */
{
if(map_file) if((k = bget_map()) == bending) error("Premature EOF in map file, %s\n", bname);
if(same[i] == i) /* if unconstrained */
{
if(map_file)
{
odata[i] = k; /* get color from background map */
}
else
{
if(color_back) /* if random color background */
{
odata[i] = ((long) rand() << 4) / RAND_MAX;
}
else /* if black and white background */
{
odata[i] = (rand() < limit) ? 0 : 255;
}
}
}
else
{
odata[i] = odata[same[i]]; /* copy cvonstrained pixel */
}
}
}
}
/* */
/* Open a grey-scale Targa for output. */
/* */
void open_targa_file(char * oname, unsigned width, unsigned height)
{
unsigned char tgaheader[18];
memset(tgaheader, 0, 18);
if ((ofile = fopen(oname, "wb")) == NULL) error("Failed to open output file %s\n", oname);
tgaheader[2] = 3;
tgaheader[12] = (unsigned char) (width & 0xFF);
tgaheader[13] = (unsigned char) ((width >> 8) & 0xFF);
tgaheader[14] = (unsigned char) (height & 0xFF);
tgaheader[15] = (unsigned char) ((height >> 8) & 0xFF);
tgaheader[16] = 8;
tgaheader[17] = 0x20;
fwrite(tgaheader, 18, 1, ofile);
}
/* */
/* Write a line of greyscale points to a Targa file */
/* */
void write_targa_line(unsigned width)
{
int i;
for (i=0;i<width;i++) fputc(odata[i], ofile);
}
/* */
/* Read and evaluate one unit of input data */
/* */
unsigned int get_value()
{
int i, j, k;
register int r, g, b;
unsigned int val;
unsigned char bytes[4];
if(intype)
{
/* */
/* get input data from GIF decoder */
/* */
if((k = idecode_gif()) < 0) error("Error reading input file %s\n", iname);
if(k == iending) return(iending);
k = k & 0xFF;
j = icmsize * k;
val = icmap[j++] << 8 | icmap[j];
}
else
{
/* */
/* get input data from TGA file */
/* */
if (ftype == 2)
{
/* */
/* input data is 8/16/24 bit rgb */
/* */
switch(ipsize)
{
case 1: if((r = fgetc(ifile)) == EOF) error("Premature EOF reading input file: %s\n", iname);
val = r << 8;
break;
case 2: if((g = fgetc(ifile)) == EOF) error("Premature EOF reading input file: %s\n", iname);
if((r = fgetc(ifile)) == EOF) error("Premature EOF reading input file: %s\n", iname);
val = r << 8 | g;
break;
case 3: if((g = fgetc(ifile)) == EOF) error("Premature EOF reading input file: %s\n", iname);
if((g = fgetc(ifile)) == EOF) error("Premature EOF reading input file: %s\n", iname);
if((r = fgetc(ifile)) == EOF) error("Premature EOF reading input file: %s\n", iname);
val = r << 8 | g;
break;
default: error("Invalid color map byte count, %i\n", ipsize);
}
}
else
{
/* */
/* input data is color map index */
/* */
if ((k = fgetc(ifile)) == EOF) error("Premature EOF reading input file: %s\n", iname);
j = icmsize * k;
if (ipsize == 2)
{
val = icmap[j++] | (icmap[j] << 8);
}
else
{
val = icmap[++j] | (icmap[++j] << 8);
}
}
}
if(direction != 0) val = -val;
return(val);
}
/* */
/* Read next byte from background map file */
/* */
unsigned int bget_map()
{
int i, j;
unsigned int k;
if((k = bdecode_gif()) < 0) error("Error reading map file %s\n", bname);
if(k == bending) return(bending);
k = k & 0xFF;
return(k);
}
/* */
/* Add index points to top of image */
/* */
void add_index(int line)
{
int i, c, d;
c = point_max - line;
d = ((xres - stripw) >> 1) - c;
for(i=0; i<c<<1; i++) odata[d+i] = 0;
d = ((xres + stripw) >> 1) - c;
for(i=0; i<c<<1; i++) odata[d+i] = 0;
}
/* */
/* Read a line's worth of the input file */
/* */
void read_data_line(int width)
{
int i, j, k;
unsigned int val;
unsigned char bytes[4];
for (i=0;i<width;i++)
{
val = get_value();
if(intype) if(val == iending) error("Premature end of object reading input GIF file %s\n", iname);
if(adapt) if(val == oldval) val = newval;
depths[i] = val;
}
}
/* */
/* Read next entry for GIF output routine */
/* */
int get_pix(int x, int y)
{
int i, val;
static int line = -1;
if(y != line)
{
line = y;
if(display == 0) printf("Line: %d \r", y);
if(line > yres) error("Request for invalid input location [%i][%i]\n", x, y);
read_data_line(xres);
gen_rds_line(xres);
if(index_points) if(y<point_max) add_index(y);
if(printer != NULL) add_line(xres, y);
test_exit;
if(display)
{
for(i=0; i<xres; i++)
{
putpixel(i, y, odata[i]);
}
}
}
val = odata[x];
return(val);
}
/* */
/* Read header portion of input file */
/* */
void read_header_data(unsigned *xsize, unsigned *ysize)
{
int i, j, k, l;
unsigned char header[18];
unsigned char bytes[4];
int width, height;
long count, val, position;
zmax = 0;
zmin = 65536;
if(fread(&header[0], 3, 1, ifile) != 1) error("Couldn't read header from input file: %s\n", iname);
intype = strncmp((const char *) header, GIFstr, 3);
intype = (intype) ? 0 : 1;
if(intype)
{
if(fread(&header[3], 10, 1, ifile) != 1) error("Couldn't read GIF header from input file %s\n", iname);
if(!(header[10] & 0x80)) error("Input file %s, has no color map\n", iname);
icmlen = 1 << ((header[10] & 0x0F) + 1);
icmsize = 3;
if (icmlen > 0)
{
if ((icmap = malloc(sizeof(unsigned char)*icmsize*icmlen)) == NULL) error("Failed to allocate memory for color map\n");
for (i=0;i<icmlen * icmsize;i++)
{
if ((k = fgetc(ifile)) == EOF) error("Premature EOF in color map\n");
icmap[i] = (unsigned char)k;
}
}
k = 0;
while(k != EOF)
{
switch(k = fgetc(ifile))
{
case ';': k = EOF;
break;
case '!': if((k = fgetc(ifile)) == EOF) error("Premature EOF in input file, %s\n", iname);
if((k = fgetc(ifile)) == EOF) error("Premature EOF in input file, %s\n", iname);
for(i=k; i>0; i--) if((k = fgetc(ifile)) == EOF) error("Premature EOF in input file, %s\n", iname);
break;
case ',': if (fread(header, 9, 1, ifile) != 1) error("Couldn't read object header from input file: %s\n", iname);
width = header[4] | header[5] << 8;
height = header[6] | header[7] << 8;
if ((header[8] & 0x80) == 0x80)
{
i = 1 << ((header[10] & 0x0F) + 1);
for(; i<0; i++) if((k = fgetc(ifile)) == EOF) error("Premature EOF in input file, %s\n", iname);
}
position = ftell(ifile);
if((k = ialloc_gif_stacks()) != 0) error("Unable to allocate stack space for GIF decoder\n");
printf("scanning GIF input for depth ranges\n");
if((val = iinit_gif_decoder()) != 0) error("Error %d, initializing GIF decoder\n", val);
while(val != iending)
{
val = get_value();
if((!adapt) || (val != oldval))
{
if(zmax < val) zmax = val;
if(zmin > val) zmin = val;
}
}
if(ibad_code_count > 0) error("%d out of range codes encountered in GIF input file %s\n", ibad_code_count, iname);
fseek(ifile, position, SEEK_SET);
if((k = iinit_gif_decoder()) != 0) error("Error %d, reinitializing GIF decoder\n", k);
k = EOF;
break;
default: error("Unknown GIF format byte - %c\n", k);
}
}
}
else
{
if(fread(&header[3], 15, 1, ifile) != 1) error("Couldn't read TGA header from input file %s\n", iname);
idlen = header[0];
ftype = header[2];
icmlen = header[5] | header[6] << 8;
icmsize = header[7];
width = header[12] | header[13] << 8;
height = header[14] | header[15] << 8;
ipsize = header[16];
if (!((ftype == 1 && ipsize <= 8) || (ftype == 2 && (ipsize == 16 || ipsize == 24)) || (ftype == 3 && ipsize == 8)))
{
error("Unsupported Targa type: %d\n", ftype);
}
if (icmlen > 256) error("Can't handle color maps of length %u\n", icmlen);
if (icmlen > 0 && (icmsize != 16 && icmsize != 24)) error("Color maps entries must be 16 or 24 bits, not: %d\n", icmsize);
else icmsize /= 8;
if (ipsize != 8 && ipsize != 16 && ipsize != 24) error("%d bits/pixel not supported in height field, must be 8/16/24\n", ipsize);
else ipsize /= 8;
if (idlen > 0 && fread(idbuf, idlen, 1, ifile) != 1) error("Reading identification field of %s\n", iname);
if (icmlen > 0)
{
if ((icmap = malloc(sizeof(unsigned char)*icmsize*icmlen)) == NULL) error("Failed to allocate memory for color map\n");
for (i=0;i<icmlen * icmsize;i++)
{
if ((k = fgetc(ifile)) == EOF) error("Premature EOF in color map\n");
icmap[i] = (unsigned char)k;
}
}
if (ftype == 1 && icmap == NULL) error("Targa color map must have entries\n");
position = ftell(ifile);
printf("scanning TGA input for depth ranges\n");
for(count= (long) width*height; count>0; count--)
{
val = get_value() & 0xFFFF;
if((!adapt) || (val != oldval))
{
if(zmax < val) zmax = val;
if(zmin > val) zmin = val;
}
}
fseek(ifile, position, SEEK_SET);
}
*xsize = width;
*ysize = height;
}
/* */
/* Read header portion of background file */
/* */
void read_background_header(unsigned *xsize, unsigned *ysize)
{
int i, j, k, l;
unsigned char header[18];
unsigned char bytes[4];
int width, height;
long count, val, position;
if(fread(&header[0], 3, 1, bfile) != 1) error("Couldn't read header from map file: %s\n", bname);
if((i = strncmp((const char *) header, GIFstr, 3)) != 0) error("Background map file, %s, is not in GIF format\n", bname);
if(fread(&header[3], 10, 1, bfile) != 1) error("Couldn't read GIF header from map file %s\n", bname);
if(!(header[10] & 0x80)) error("Background map file %s, has no color map\n", bname);
bcmlen = 1 << ((header[10] & 0x0F) + 1);
bcmsize = 3;
if (bcmlen > 0)
{
if ((bcmap = malloc(sizeof(unsigned char)*bcmsize*bcmlen)) == NULL) error("Failed to allocate memory for color map\n");
for (i=0;i<bcmlen * bcmsize;i++)
{
if ((k = fgetc(bfile)) == EOF) error("Premature EOF in color map\n");
bcmap[i] = (unsigned char)k;
}
}
k = 0;
while(k != EOF)
{
switch(k = fgetc(bfile))
{
case ';': k = EOF;
break;
case '!': if((k = fgetc(bfile)) == EOF) error("Premature EOF in map file, %s\n", bname);
if((k = fgetc(bfile)) == EOF) error("Premature EOF in map file, %s\n", bname);
for(i=k; i>0; i--) if((k = fgetc(bfile)) == EOF) error("Premature EOF in map file, %s\n", bname);
break;
case ',': if (fread(header, 9, 1, bfile) != 1) error("Couldn't read object header from map file: %s\n", bname);
width = header[4] | header[5] << 8;
height = header[6] | header[7] << 8;
*xsize = width;
*ysize = height;
if ((header[8] & 0x80) == 0x80)
{
i = 1 << ((header[10] & 0x0F) + 1);
for(; i<0; i++) if((k = fgetc(bfile)) == EOF) error("Premature EOF in map file, %s\n", bname);
}
if((k = balloc_gif_stacks()) != 0) error("Unable to allocate stack space for GIF decoder\n");
if((k = binit_gif_decoder()) != 0) error("Error %d, initializing GIF decoder\n", k);
k = EOF;
break;
default: error("Unknown GIF format byte - %c\n", k);
}
}
}
/* */
/* Generate RDS from Targa depth data */
/* */
void TGAEncode(char * oname, int width, int height)
{
int i, j;
open_targa_file(oname, width, height);
for (i=height;i>0;i--)
{
if(display == 0) printf("Line: %d \r", i);
read_data_line(width);
gen_rds_line(xres);
if(index_points) if(i<point_max) add_index(i);
if(printer != NULL) add_line(xres, i);
if(display)
{
for(j=0; j<width; j++)
{
if(odata[j] == 255) putpixel(j, height-i-1, WHITE);
}
}
test_exit;
write_targa_line(width);
}
fclose(ofile);
}
/* */
/* Display command line parameters */
/* */
void showparms()
{
printf("\nUsage: rds input.ext output.ext options\n\n");
printf("options: -a# : Algirithm number, range 1 or 2 (default 1)\n");
printf(" -b### : Adaptive background value, range 1 to 64\n");
printf(" -d### : Density value, range 0 to 100 (default 50)\n");
printf(" -i : Add indexing triangles to top of RDS\n");
printf(" -mccc.ext : Background map file name\n");
printf(" -n : Produce a precedence reversed (negative) image\n");
printf(" -pcc : Print image on named graphics printer\n");
printf(" -r##### : Seed number for random generator, range 1-32767 (default 1)\n");
printf(" -s### : Strip count, range 1-width (default 8)\n");
printf(" -t : Generate type 3 TGA output file\n");
printf(" -v : Display image on video while processing\n\n");
}
/* */
/* Add line to printer array */
/* */
void add_line(int width, int line)
{
int i, j, k;
unsigned int c;
k = 0;
if((printx = (unsigned char *) malloc(width >> 3)) == NULL) error("Unable to allocate print line %i\n", line);
printy[line] = printx;
for(i=0; i<width;)
{
c = 0;
for(j=0; j<8; j++)
{
if((printer[0] == 'e') || (printer[0] == 'E'))
{
c = c >> 1;
if(odata[i++] == 0) c += 0x80;
}
else
{
c = c << 1;
if(odata[i++] == 0) c++;
}
}
printx[k++] = c;
}
}
/* */
/* Print RDS on graphics printer */
/* */
void printout()
{
switch(printer[0])
{
case 'e' :
case 'E' : epsonout();
break;
case 'h' :
case 'H' : hewlettout();
break;
default : error("Unsupported printer type, %s\n", printer);
}
}
/* */
/* Print RDS on epson 8/24-pin dot matrix printer */
/* incomplete */
void epsonout()
{
int i, j, k;
char init_prt[] = { 0x1B, '3', 0x18, '\0' };
char init_line[] = { 0x1B, 'L', '\0', '\0' };
init_line[2] = (yres << 1) & 0xFF;
init_line[3] = (yres >> 7);
for(i=0; i<3; i++) biosprint(PR_OUT, init_prt[i], LPT1);
for(i=(xres>>3)-1; i>=0; i--)
{
for(j=0; j<4; j++) biosprint(PR_OUT, init_line[j], LPT1);
for(j=0; j<yres; j++)
{
printx = printy[j];
biosprint(PR_OUT, printx[i], LPT1);
biosprint(PR_OUT, printx[i], LPT1);
}
biosprint(PR_OUT, 0x0D, LPT1);
biosprint(PR_OUT, 0x0A, LPT1);
}
}
/* */
/* Print RDS on Hewlett Packard Laser Jet */
/* incomplete */
void hewlettout()
{
int i, j, k;
int xinc, yinc, inc;
int left, top;
unsigned char * byte;
char * ctop;
char * cleft;
char init_res[] = { 0x1B, '*', 't', '3', '0', '0', 'R' };
char set_top[] = { 0x1B, '&', 'a', '\0', '\0', '\0', 'R' };
char set_left[] = { 0x1B, '&', 'a', '\0', '\0', '\0', 'H' };
char init_line[] = { 0x1B, '*', '1', 'A' };
char send_line[] = { 0x1B, '*', 'b', '\0', '\0', '\0', 'W' };
char end_graph[] = { 0x1B, '*', 'r', 'B' };
xinc = 3000/xres;
yinc = 2400/yres;
inc = (xinc < yinc) ? xinc : yinc;
top = (39600L - ((long) inc * xres * 12)) / 10;
left = (30600L - ((long) inc * xres * 12)) / 10;
ctop = itoa(top, ctop, 10);
cleft = itoa(left, cleft, 10);
strncpy(set_top[3], ctop, 3);
strncpy(set_left[3], cleft, 3);
for(i=0; i<7; i++) biosprint(PR_OUT, init_res[i], LPT1);
for(i=0; i<7; i++) biosprint(PR_OUT, set_top[i], LPT1);
for(i=0; i<7; i++) biosprint(PR_OUT, set_left[i], LPT1);
for(i=0; i<5; i++) biosprint(PR_OUT, init_res[i], LPT1);
for(i=(xres>>3)-1; i>=0; i--)
{
for(j=0; j<yres; j++)
{
printx = printy[j];
for(k=0; k<4; k++) biosprint(PR_OUT, init_line[k], LPT1);
for(k=0; k<7; k++) biosprint(PR_OUT, send_line[k], LPT1);
for(k=0; k<inc; k++)
{
/* need some code here */
}
}
}
for(i=0; i<4; i++) biosprint(PR_OUT, end_graph[i], LPT1);
}
/* */
/* Beep, beep */
/* */
void beep()
{
nosound();
sound(1300);
delay(80);
sound(1600);
delay(80);
sound(1900);
delay(80);
nosound();
}
/* */
/* Display error message and exit */
/* */
void error(char *format, ...)
{
va_list parms;
/* fg_term(); */
fprintf(stdout, "ERROR: ");
va_start(parms, format);
vfprintf(stdout, format, parms);
va_end(parms);
if(display) closegraph();
exit(1);
}
/* */
/* GIF decoding routine */
/* */
/* This routine was borrowed from POVRAY which in turn borrowed the code */
/* from FRACTINT. It appears here in a somewhat modified format to */
/* conform to the requirements of my output driven logic. Nevertheless, */
/* I must give give appropriate credit to the orignal authors. */
/* */
/* Based on : DECODER.C - An LZW decoder for GIF */
/* Written by Steven A. Bennett */
/* As inspired by Steve Wilhite */
/* And modified by Bert Tyler and Timothy Wegner */
/* */
/* */
/* Get next byte of input for GIF decoder */
/* */
int iget_byte()
{
int b;
if((b = fgetc(ifile)) != EOF) return(b);
printf("Premature EOF in GIF input file %s\n", iname);
return(b);
}
/* */
/* get the next code from the GIF file */
/* */
WORD iget_next_code()
{
WORD i, x;
ULONG ret;
if (ibit_count == 0)
{
if (ibyte_count <= 0)
{
/* Out of bytes in current block, so read next block */
ibyte_ptr = ibyte_buff;
if ((ibyte_count = iget_byte()) < 0) return(ibyte_count);
else if (ibyte_count)
{
for (i = 0; i < ibyte_count; ++i)
{
if ((x = iget_byte()) < 0) return(x);
ibyte_buff[i] = (UTINY) x;
}
}
}
ibyte = *ibyte_ptr++;
ibit_count = 8;
--ibyte_count;
}
ret = ibyte >> (8 - ibit_count);
while (icurr_size > ibit_count)
{
if (ibyte_count <= 0)
{
/* Out of bytes in current block, so read next block */
ibyte_ptr = ibyte_buff;
if ((ibyte_count = iget_byte()) < 0) return(ibyte_count);
else if (ibyte_count)
{
for (i = 0; i < ibyte_count; ++i)
{
if ((x = iget_byte()) < 0) return(x);
ibyte_buff[i] = (UTINY) x;
}
}
}
ibyte = *ibyte_ptr++;
ret |= ibyte << ibit_count;
ibit_count += 8;
--ibyte_count;
}
ibit_count -= icurr_size;
ret &= code_mask[icurr_size];
return((WORD)(ret));
}
/* */
/* Allocate stacks */
/* */
int ialloc_gif_stacks()
{
idstack = (UTINY *) malloc((MAX_CODES + 1)*sizeof(UTINY));
isuffix = (UTINY *) malloc((MAX_CODES + 1)*sizeof(UTINY));
iprefix = (UWORD *) malloc((MAX_CODES + 1)*sizeof(UWORD));
return(0);
}
/* */
/* Release stacks */
/* */
void ifree_gif_stacks()
{
free(idstack);
free(isuffix);
free(iprefix);
}
/* */
/* Initialize for decoding a new image */
/* */
int iinit_gif_decoder()
{
int i, ret;
ret = 0;
if ((icode_size = iget_byte()) < 0) return(icode_size);
if (icode_size < 2 || 9 < icode_size) return(BAD_CODE_SIZE);
icurr_size = icode_size + 1;
itop_slot = 1 << icurr_size;
iclear = 1 << icode_size;
iending = iclear + 1;
islot = inew_codes = iending + 1;
ibyte_count = ibit_count = 0;
/* Initialize in case they forgot to put in a clear code. */
/* (This shouldn't happen, but we'll try and decode it anyway...) */
iold_code = iout_value = 0;
ibad_code_count = 0;
/* Set up the stack pointer and decode buffer pointer */
iemit_index = idstack;
for(i=0; i<MAX_CODES+1; i++) iprefix[i] = 0;
for(i=0; i<MAX_CODES+1; i++) isuffix[i] = 0;
return(ret);
}
/* */
/* Get next byte from GIF decoder */
/* */
int idecode_gif()
{
register int c;
register int code;
/* This is the main loop. For each code we get we pass through the
* linked list of iprefix codes, pushing the corresponding "character" for
* each code onto the stack. When the list reaches a single "character"
* we push that on the stack too, and then start unstacking each
* character for output in the correct order. Special handling is
* included for the clear code, and the whole thing ends when we get
* an ending code.
*/
if(iemit_index > idstack) return(*(--iemit_index));
while ((c = iget_next_code()) != iending)
{
/* If we had a file error, return without completing the decode */
if(c < 0)
return(0);
/* If the code is a clear code, reinitialize all necessary items */
if(c == iclear)
{
icurr_size = icode_size + 1;
islot = inew_codes;
itop_slot = 1 << icurr_size;
/* Continue reading codes until we get a non-clear code */
/* (Another unlikely, but possible case...) */
while ((c = iget_next_code()) == iclear);
/* If we get an ending code immediately after a clear code */
/* (Yet another unlikely case), then break out of the loop. */
if(c == iending) break;
/* Finally, if the code is beyond the range of already set */
/* codes, (This one had better NOT happen... I have no idea */
/* what will result from this, but I doubt it will look good... */
/* then set it to color zero */
if(c >= islot) c = 0;
iold_code = iout_value = c;
/* And let us not forget to put the character into the buffer */
return(c);
}
else
{
/* In this case, it's not a clear code or an ending code, so */
/* it must be a code code... So we can now decode the code into */
/* a stack of character codes. (Clear as mud, right?) */
code = c;
/* Here we go again with one of those off chances... If, on the */
/* off chance, the code we got is beyond the range of those already */
/* set up (Another thing which had better NOT happen...) we trick */
/* the decoder into thinking it actually got the last code read. */
/* (Hmmn... I'm not sure why this works... But it does...) */
if(code >= islot)
{
if(code > islot) ++ibad_code_count;
code = iold_code;
*iemit_index++ = (UTINY) iout_value;
}
/* Here we scan back along the linked list of iprefixes, pushing */
/* helpless characters (ie. isuffixes) onto the stack as we do so. */
while (code >= inew_codes)
{
*iemit_index++ = isuffix[code];
code = iprefix[code];
}
/* Push the last character on the stack, and set up the new */
/* iprefix and isuffix, and if the required slot number is greater */
/* than that allowed by the current bit size, increase the bit */
/* size. (NOTE - If we are all full, we *don't* save the new */
/* isuffix and iprefix... I'm not certain if this is correct... */
/* it might be more proper to overwrite the last code... */
*iemit_index++ = (UTINY) code;
if(islot < itop_slot)
{
iout_value = code;
isuffix[islot] = (UTINY) iout_value;
iprefix[islot++] = iold_code;
iold_code = c;
}
if(islot >= itop_slot)
{
if(icurr_size < 12)
{
itop_slot <<= 1;
++icurr_size;
}
}
/* Now that we've pushed the decoded string (in reverse order) */
/* onto the stack, lets pop it off and return it a byte at a */
/* time to the caller */
if(iemit_index > idstack) return(*(--iemit_index));
}
}
return(c);
}
/* */
/* Get next byte of input for GIF decoder */
/* */
int bget_byte()
{
int b;
if((b = fgetc(bfile)) != EOF) return(b);
printf("Premature EOF in GIF background file %s\n", bname);
return(b);
}
/* */
/* get the next code from the background GIF file */
/* */
WORD bget_next_code()
{
WORD i, x;
ULONG ret;
if (bbit_count == 0)
{
if (bbyte_count <= 0)
{
/* Out of bytes in current block, so read next block */
bbyte_ptr = bbyte_buff;
if ((bbyte_count = bget_byte()) < 0) return(bbyte_count);
else if (bbyte_count)
{
for (i = 0; i < bbyte_count; ++i)
{
if ((x = bget_byte()) < 0) return(x);
bbyte_buff[i] = (UTINY) x;
}
}
}
bbyte = *bbyte_ptr++;
bbit_count = 8;
--bbyte_count;
}
ret = bbyte >> (8 - bbit_count);
while (bcurr_size > bbit_count)
{
if (bbyte_count <= 0)
{
/* Out of bytes in current block, so read next block */
bbyte_ptr = bbyte_buff;
if ((bbyte_count = bget_byte()) < 0) return(bbyte_count);
else if (bbyte_count)
{
for (i = 0; i < bbyte_count; ++i)
{
if ((x = bget_byte()) < 0) return(x);
bbyte_buff[i] = (UTINY) x;
}
}
}
bbyte = *bbyte_ptr++;
ret |= bbyte << bbit_count;
bbit_count += 8;
--bbyte_count;
}
bbit_count -= bcurr_size;
ret &= code_mask[bcurr_size];
return((WORD)(ret));
}
/* */
/* Allocate stacks */
/* */
int balloc_gif_stacks()
{
bdstack = (UTINY *) malloc((MAX_CODES + 1)*sizeof(UTINY));
bsuffix = (UTINY *) malloc((MAX_CODES + 1)*sizeof(UTINY));
bprefix = (UWORD *) malloc((MAX_CODES + 1)*sizeof(UWORD));
return(0);
}
/* */
/* Release stacks */
/* */
void bfree_gif_stacks()
{
free(bdstack);
free(bsuffix);
free(bprefix);
}
/* */
/* Initialize for decoding a new image */
/* */
int binit_gif_decoder()
{
int i, ret;
ret = 0;
if ((bcode_size = bget_byte()) < 0) return(bcode_size);
if (bcode_size < 2 || 9 < bcode_size) return(BAD_CODE_SIZE);
bcurr_size = bcode_size + 1;
btop_slot = 1 << bcurr_size;
bclear = 1 << bcode_size;
bending = bclear + 1;
bslot = bnew_codes = bending + 1;
bbyte_count = bbit_count = 0;
/* Initialize in case they forgot to put in a clear code. */
/* (This shouldn't happen, but we'll try and decode it anyway...) */
bold_code = bout_value = 0;
bbad_code_count = 0;
/* Set up the stack pointer and decode buffer pointer */
bemit_index = bdstack;
for(i=0; i<MAX_CODES+1; i++) bprefix[i] = 0;
for(i=0; i<MAX_CODES+1; i++) bsuffix[i] = 0;
return(ret);
}
/* */
/* Get next byte from GIF decoder */
/* */
int bdecode_gif()
{
register int c;
register int code;
/* This is the main loop. For each code we get we pass through the
* linked list of iprefix codes, pushing the corresponding "character" for
* each code onto the stack. When the list reaches a single "character"
* we push that on the stack too, and then start unstacking each
* character for output in the correct order. Special handling is
* included for the clear code, and the whole thing ends when we get
* an ending code.
*/
if(bemit_index > bdstack) return(*(--bemit_index));
while ((c = bget_next_code()) != bending)
{
/* If we had a file error, return without completing the decode */
if(c < 0)
return(0);
/* If the code is a clear code, reinitialize all necessary items */
if(c == bclear)
{
bcurr_size = bcode_size + 1;
bslot = bnew_codes;
btop_slot = 1 << bcurr_size;
/* Continue reading codes until we get a non-clear code */
/* (Another unlikely, but possible case...) */
while ((c = bget_next_code()) == bclear);
/* If we get an ending code immediately after a clear code */
/* (Yet another unlikely case), then break out of the loop. */
if(c == bending) break;
/* Finally, if the code is beyond the range of already set */
/* codes, (This one had better NOT happen... I have no idea */
/* what will result from this, but I doubt it will look good... */
/* then set it to color zero */
if(c >= bslot) c = 0;
bold_code = bout_value = c;
/* And let us not forget to put the character into the buffer */
return(c);
}
else
{
/* In this case, it's not a clear code or an ending code, so */
/* it must be a code code... So we can now decode the code into */
/* a stack of character codes. (Clear as mud, right?) */
code = c;
/* Here we go again with one of those off chances... If, on the */
/* off chance, the code we got is beyond the range of those already */
/* set up (Another thing which had better NOT happen...) we trick */
/* the decoder into thinking it actually got the last code read. */
/* (Hmmn... I'm not sure why this works... But it does...) */
if(code >= bslot)
{
if(code > bslot) ++bbad_code_count;
code = bold_code;
*bemit_index++ = (UTINY) bout_value;
}
/* Here we scan back along the linked list of iprefixes, pushing */
/* helpless characters (ie. isuffixes) onto the stack as we do so. */
while (code >= bnew_codes)
{
*bemit_index++ = bsuffix[code];
code = bprefix[code];
}
/* Push the last character on the stack, and set up the new */
/* iprefix and isuffix, and if the required slot number is greater */
/* than that allowed by the current bit size, increase the bit */
/* size. (NOTE - If we are all full, we *don't* save the new */
/* isuffix and iprefix... I'm not certain if this is correct... */
/* it might be more proper to overwrite the last code... */
*bemit_index++ = (UTINY) code;
if(bslot < btop_slot)
{
bout_value = code;
bsuffix[bslot] = (UTINY) bout_value;
bprefix[bslot++] = bold_code;
bold_code = c;
}
if(bslot >= btop_slot)
{
if(bcurr_size < 12)
{
btop_slot <<= 1;
++bcurr_size;
}
}
/* Now that we've pushed the decoded string (in reverse order) */
/* onto the stack, lets pop it off and return it a byte at a */
/* time to the caller */
if(bemit_index > bdstack) return(*(--bemit_index));
}
}
return(c);
}
/******************************************************************************
*
* GIF output routines
*
******************************************************************************/
/* Number of characters so far in this 'packet' */
static int a_count;
/* Set up the 'byte output' routine */
void char_init()
{
a_count = 0;
}
/* Define the storage for the packet accumulator */
static char accum[ 256 ];
/*
* Add a character to the end of the current packet, and if it is 254
* characters, flush the packet to disk.
*/
void char_out( c )
int c;
{
accum[ a_count++ ] = c;
if( a_count >= 254 )
flush_char();
}
/*
* Flush the packet to disk, and reset the accumulator
*/
void flush_char()
{
if( a_count > 0 ) {
fputc( a_count, g_outfile );
fwrite( accum, 1, a_count, g_outfile );
a_count = 0;
}
}
/* */
/* Write out a word to the GIF file */
/* */
void Putword(int w, FILE *fp )
{
fputc( w & 0xff, fp );
fputc( (w / 256) & 0xff, fp );
}
/*
* Bump the 'curx' and 'cury' to point to the next pixel
*/
static void BumpPixel()
{
/*
* Bump the current X position
*/
curx++;
/*
* If we are at the end of a scan line, set curx back to the beginning
* If we are interlaced, bump the cury to the appropriate spot,
* otherwise, just increment it.
*/
if( curx == Width ) {
curx = 0;
if( !Interlace )
cury++;
else {
switch( Pass ) {
case 0:
cury += 8;
if( cury >= Height ) {
Pass++;
cury = 4;
}
break;
case 1:
cury += 8;
if( cury >= Height ) {
Pass++;
cury = 2;
}
break;
case 2:
cury += 4;
if( cury >= Height ) {
Pass++;
cury = 1;
}
break;
case 3:
cury += 2;
break;
}
}
}
}
/*
* Return the next pixel from the image
*/
int GIFNextPixel(getpixel)
ifunptr getpixel;
{
int r;
if( CountDown == 0 )
return EOF;
CountDown--;
r = getpixel( curx, cury );
BumpPixel();
return r;
}
/* public */
void GIFEncode( FName, GWidth, GHeight, GInterlace, Background,
BitsPerPixel, Red, Green, Blue, GetPixel )
char * FName;
int GWidth, GHeight;
int GInterlace;
int Background;
int BitsPerPixel;
int Red[], Green[], Blue[];
ifunptr GetPixel;
{
FILE *fp;
int B;
int RWidth, RHeight;
int LeftOfs, TopOfs;
int Resolution;
int ColorMapSize;
int InitCodeSize;
int i;
Interlace = GInterlace;
ColorMapSize = 1 << BitsPerPixel;
RWidth = Width = GWidth;
RHeight = Height = GHeight;
LeftOfs = TopOfs = 0;
Resolution = BitsPerPixel;
/*
* Calculate number of bits we are expecting
*/
CountDown = (long)Width * (long)Height;
/*
* Indicate which pass we are on (if interlace)
*/
Pass = 0;
/*
* The initial code size
*/
if( BitsPerPixel <= 1 )
InitCodeSize = 2;
else
InitCodeSize = BitsPerPixel;
/*
* Set up the current x and y position
*/
curx = cury = 0;
/*
* Open the GIF file for binary write
*/
fp = fopen( FName, "wb" );
if( fp == (FILE *)0 ) {
printf( "error: could not open output file\n" );
exit(1);
}
/*
* Write the Magic header
*/
fwrite( "GIF87a", 1, 6, fp );
/*
* Write out the screen width and height
*/
Putword( RWidth, fp );
Putword( RHeight, fp );
/*
* Indicate that there is a global colour map
*/
B = 0x80; /* Yes, there is a color map */
/*
* OR in the resolution
*/
B |= (Resolution - 1) << 5;
/*
* OR in the Bits per Pixel
*/
B |= (BitsPerPixel - 1);
/*
* Write it out
*/
fputc( B, fp );
/*
* Write out the Background colour
*/
fputc( Background, fp );
/*
* Byte of 0's (future expansion)
*/
fputc( 0, fp );
/*
* Write out the Global Colour Map
*/
for( i=0; i<ColorMapSize; i++ ) {
fputc( Red[i], fp );
fputc( Green[i], fp );
fputc( Blue[i], fp );
}
/*
* Write an Image separator
*/
fputc( ',', fp );
/*
* Write the Image header
*/
Putword( LeftOfs, fp );
Putword( TopOfs, fp );
Putword( Width, fp );
Putword( Height, fp );
/*
* Write out whether or not the image is interlaced
*/
if( Interlace )
fputc( 0x40, fp );
else
fputc( 0x00, fp );
/*
* Write out the initial code size
*/
fputc( InitCodeSize, fp );
/*
* Go and actually compress the data
*/
compress( InitCodeSize+1, fp, GetPixel );
/*
* Write out a Zero-length packet (to end the series)
*/
fputc( 0, fp );
/*
* Write the GIF file terminator
*/
fputc( ';', fp );
/*
* And close the file
*/
fclose(fp);
}
/* */
/* GIF encoding routine */
/* */
/* This routine was borrowed from TGA2GIF with very little modification */
/* I must give credit to the original authors for their highly useful code */
/* */
/* Based on : GIFENCODE.C - An LZW encoder for GIF */
/* Written by Steven B. Coy */
/* From code by David Rowley */
/* And modified by Drew Wells and Chris Cason */
/* */
/*
* GIF Image compression - modified 'compress'
*
* Based on: compress.c - File compression ala IEEE Computer, June 1984.
*
* By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
* Jim McKie (decvax!mcvax!jim)
* Steve Davies (decvax!vax135!petsd!peora!srd)
* Ken Turkowski (decvax!decwrl!turtlevax!ken)
* James A. Woods (decvax!ihnp4!ames!jaw)
* Joe Orost (decvax!vax135!petsd!joe)
*
*/
/*
* compress stdin to stdout
*
* Algorithm: use open addressing double hashing (no chaining) on the
* iprefix code / next character combination. We do a variant of Knuth's
* algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
* secondary probe. Here, the modular division first probe is gives way
* to a faster exclusive-or manipulation. Also do block compression with
* an adaptive reset, whereby the code table is cleared when the compression
* ratio decreases, but after the table fills. The variable-length output
* codes are re-sized at this point, and a special CLEAR code is generated
* for the decompressor. Late addition: construct the table according to
* file size for noticeable speed improvement on small files. Please direct
* questions about this implementation to ames!jaw.
*/
compress( init_bits, outfile, ReadValue )
int init_bits;
FILE *outfile;
ifunptr ReadValue;
{
register long fcode;
register code_int i = 0;
register int c;
register code_int ent;
register code_int disp;
register code_int hsize_reg;
register int hshift;
/*
* Set up the globals: g_init_bits - initial number of bits
* g_outfile - pointer to output file
*/
g_init_bits = init_bits;
g_outfile = outfile;
/*
* Set up the necessary values
*/
offset = 0;
out_count = 0;
clear_flg = 0;
in_count = 1;
maxcode = MAXCODE(n_bits = g_init_bits);
ClearCode = (1 << (init_bits - 1));
EOFCode = ClearCode + 1;
free_ent = ClearCode + 2;
char_init();
ent = GIFNextPixel( ReadValue );
hshift = 0;
for ( fcode = (long) hsize; fcode < 65536L; fcode *= 2L )
hshift++;
hshift = 8 - hshift; /* set hash code range bound */
hsize_reg = hsize;
cl_hash( (count_int) hsize_reg); /* clear hash table */
output( (code_int)ClearCode );
#ifdef SIGNED_COMPARE_SLOW
while ( (c = GIFNextPixel( ReadValue )) != (unsigned) EOF ) {
#else
while ( (c = GIFNextPixel( ReadValue )) != EOF ) {
#endif
in_count++;
fcode = (long) (((long) c << maxbits) + ent);
i = (((code_int)c << hshift) ^ ent); /* xor hashing */
if ( HashTabOf (i) == fcode ) {
ent = CodeTabOf (i);
continue;
} else if ( (long)HashTabOf (i) < 0 ) /* empty slot */
goto nomatch;
disp = hsize_reg - i; /* secondary hash (after G. Knott) */
if ( i == 0 )
disp = 1;
probe:
if ( (i -= disp) < 0 )
i += hsize_reg;
if ( HashTabOf (i) == fcode ) {
ent = CodeTabOf (i);
continue;
}
if ( (long)HashTabOf (i) > 0 )
goto probe;
nomatch:
output ( (code_int) ent );
out_count++;
ent = c;
#ifdef SIGNED_COMPARE_SLOW
if ( (unsigned) free_ent < (unsigned) maxmaxcode) {
#else
if ( free_ent < maxmaxcode ) {
#endif
CodeTabOf (i) = free_ent++; /* code -> hashtable */
HashTabOf (i) = fcode;
} else
cl_block();
}
/*
* Put out the final code.
*/
output( (code_int)ent );
out_count++;
output( (code_int) EOFCode );
return 0;
}
/*****************************************************************
* TAG( output )
*
* Output the given code.
* Inputs:
* code: A n_bits-bit integer. If == -1, then EOF. This assumes
* that n_bits =< (long)wordsize - 1.
* Outputs:
* Outputs code to the file.
* Assumptions:
* Chars are 8 bits long.
* Algorithm:
* Maintain a BITS character long buffer (so that 8 codes will
* fit in it exactly). Use the VAX insv instruction to insert each
* code in turn. When the buffer fills up empty it and start over.
*/
void output( code )
code_int code;
{
cur_accum &= code_mask[ cur_bits ];
if( cur_bits > 0 )
cur_accum |= ((long)code << cur_bits);
else
cur_accum = code;
cur_bits += n_bits;
while( cur_bits >= 8 ) {
char_out( (unsigned int)(cur_accum & 0xff) );
cur_accum >>= 8;
cur_bits -= 8;
}
/*
* If the next entry is going to be too big for the code size,
* then increase it, if possible.
*/
if ( free_ent > maxcode || clear_flg ) {
if( clear_flg ) {
maxcode = MAXCODE (n_bits = g_init_bits);
clear_flg = 0;
} else {
n_bits++;
if ( n_bits == maxbits )
maxcode = maxmaxcode;
else
maxcode = MAXCODE(n_bits);
}
}
if( code == EOFCode ) {
/*
* At EOF, write the rest of the buffer.
*/
while( cur_bits > 0 ) {
char_out( (unsigned int)(cur_accum & 0xff) );
cur_accum >>= 8;
cur_bits -= 8;
}
flush_char();
fflush( g_outfile );
if( ferror( g_outfile ) )
writeerr();
}
}
/*
* Clear out the hash table
*/
void cl_block () /* table clear for block compress */
{
cl_hash ( (count_int) hsize );
free_ent = ClearCode + 2;
clear_flg = 1;
output( (code_int)ClearCode );
}
void cl_hash(hsize) /* reset code table */
register count_int hsize;
{
register count_int *htab_p = htab+hsize;
register long i;
register long m1 = -1;
i = hsize - 16;
do { /* might use Sys V memset(3) here */
*(htab_p-16) = m1;
*(htab_p-15) = m1;
*(htab_p-14) = m1;
*(htab_p-13) = m1;
*(htab_p-12) = m1;
*(htab_p-11) = m1;
*(htab_p-10) = m1;
*(htab_p-9) = m1;
*(htab_p-8) = m1;
*(htab_p-7) = m1;
*(htab_p-6) = m1;
*(htab_p-5) = m1;
*(htab_p-4) = m1;
*(htab_p-3) = m1;
*(htab_p-2) = m1;
*(htab_p-1) = m1;
htab_p -= 16;
} while ((i -= 16) >= 0);
for ( i += 16; i > 0; i-- )
*--htab_p = m1;
}
void writeerr()
{
printf( "error writing output file\n" );
exit(1);
}