home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 8 Other
/
08-Other.zip
/
GIFDEV.ZIP
/
TGIF.C
< prev
next >
Wrap
C/C++ Source or Header
|
1989-04-10
|
16KB
|
785 lines
/*
** tgif.c : Two-tone GIF file display utilty
**
** Written by: James Lark
** 6101 W. Courtyard Dr.
** Austin, Tx. 78730
**
*/
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <bios.h>
#include <graphics.h>
#include <dos.h>
#include <malloc.h>
#include <io.h>
#define YES 1
#define NO 0
#define tab1 6
#define tab2 26
#define tab3 46
#define tab4 66
#define fbits 32
struct {
char t_code;
int t_link;
} root_tab[4097];
unsigned nroots;
char str_buf[4097];
unsigned str_len;
unsigned cur_bct, eof_bct, clr_code, eoi_code;
unsigned old_code, cur_mask, cur_bits, tab_stor;
FILE *giffile;
long giffilen;
char fname[30];
unsigned ras_wid, ras_high;
unsigned glob_cfg;
unsigned glob_bgc;
int intens[256];
int grey_level;
int c_white,c_black;
int pix_black = 0;
int pix_white = 1;
unsigned img_csz;
unsigned img_cfg;
unsigned ilace;
unsigned img_top, img_left;
unsigned img_wid, img_high;
unsigned pix_wid, pix_high;
unsigned pix_bwid;
int dot_row, dot_col;
int vid_mask;
int *ras_line;
int *rlp;
int pix_diag;
char far *pix_buf;
unsigned long pix_base;
unsigned long code_six;
char *savl;
int savlix;
int max_pcr;
unsigned long mav_codes, mav_length;
int i_leave, i_phase;
int opt_w, opt_l;
int opt_c;
int opt_t;
unsigned ngifrecs;
unsigned long ngifcodes;
int mygetc()
{
if( !feof(giffile) ) return fgetc( giffile );
setvmode( 3 );
curson();
clrscrn();
printf( "\nEOF on input!!\n" );
exit( 0 );
}
void msg_rc( int row, int col, char *msg )
{
poscurs( row, col );
printf( "%s", msg );
}
void msg_rcn( int row, int col, unsigned num )
{
char text[20];
sprintf( text, "%-5u", num );
msg_rc( row, col, text );
}
void msg_rcl( int row, int col, unsigned long num )
{
char text[20];
sprintf( text, "%-8lu", num );
msg_rc( row, col, text );
}
int gifsig_ok()
{
int i;
char prefix[4];
for( i=0; i!=3; i++ ) prefix[i] = mygetc();
prefix[3] = '\0';
if( strcmpi( "gif", prefix ) == 0 ) {
msg_rc( 4, tab3, "GIF signature:" );
msg_rc( 4, tab4, "GIF" );
for( i=0; i!=3; i++ ) prefix[i] = mygetc();
prefix[4] = '\0';
msg_rc( 4, tab4+3, prefix );
return YES;
}
return NO;
}
int gifscd()
{
ras_wid = mygetc() | (mygetc() << 8);
msg_rc( 5, tab1, "Raster width:" );
msg_rcn( 5, tab2, ras_wid );
ras_high = mygetc() | (mygetc() << 8);
msg_rc( 6, tab1, "Raster height:" );
msg_rcn( 6, tab2, ras_high );
glob_cfg = mygetc();
msg_rc( 5, tab3, "Bits per pixel:" );
msg_rcn( 5, tab4, (glob_cfg & 7)+1 );
if( glob_cfg && 128 ) msg_rc( 6, tab3, "Global color map present." );
else msg_rc( 6, tab3, "Global color map not present." );
glob_bgc = mygetc();
msg_rc( 7, tab1, "Background color:" );
msg_rcn( 7, tab2, glob_bgc );
if( mygetc() == 0 ) return YES;
return NO;
}
void gif_cmap()
{
int i, k;
unsigned gll;
grey_level = 128;
if( glob_cfg & 128 ) {
gll = 0;
c_black = 256;
c_white = 0;
k = 1 << ((glob_cfg & 7)+1) ;
msg_rc( 7, tab3, "Color map entries:" );
msg_rcn( 7, tab4, k );
for( i=0; i!=k; i++ ) {
intens[i] =(mygetc()+mygetc()+mygetc())/3;
gll += intens[i];
if( intens[i] > c_white ) c_white = intens[i];
if( intens[i] < c_black ) c_black = intens[i];
intens[i] = intens[i]*fbits;
}
grey_level = (gll / k)*fbits;
c_white *= fbits;
c_black *= fbits;
}
}
void gif_ext()
{
int i;
while( i = mygetc() ) {
while( i-- ) mygetc();
}
}
void rooter()
{
int i;
cur_bct = 0;
eof_bct = NO;
nroots = 1 << img_csz;
clr_code = nroots;
eoi_code = nroots+1;
for( i = 0; i != nroots; i++) {
root_tab[i].t_code = i;
root_tab[i].t_link = -1;
}
}
void set_mask()
{
cur_bits = img_csz+1;
tab_stor = 0;
cur_mask = nroots+nroots-1;
}
void sbar( long percent )
{
int i;
poscurs( 21, 20 );
i = percent;
while( i-- ) printf( "%c", 219 );
i = 40-percent;
while( i-- ) printf( "%c", 176 );
}
void setcsts()
{
msg_rc( 13, tab1, "Records processed:" );
msg_rcn( 13, tab2, ngifrecs++ );
msg_rc( 13, tab3, "Codes unpacked:" );
msg_rcl( 13, tab4, ngifcodes );
msg_rc( 15, tab1, "Max. compression:" );
msg_rcn( 15, tab2, max_pcr );
msg_rc( 15, tab3, "Avg. compression:" );
if( mav_length != 0 ) msg_rcl( 15, tab4, (mav_length+(mav_length>>1))/mav_codes );
else msg_rcn( 15, tab4, 0 );
}
unsigned gnxcic()
{
long bperc;
if( cur_bct == 0 ) {
setcsts();
bperc = 40l * ftell( giffile ) / giffilen ;
sbar( bperc );
if( ((cur_bct = mygetc()) == 0) || eof_bct ) {
eof_bct = YES;
return 0;
}
}
cur_bct -= 1;
return mygetc();
}
int mem_setup()
{
unsigned long pix_size;
savlix = 0;
if( opt_t ) {
pix_wid = img_wid * 3;
pix_high = img_high * 3;
}
else {
if( opt_w ) pix_wid = img_wid + img_wid;
else pix_wid = img_wid;
if( opt_l ) pix_high = img_high + img_high;
else pix_high = img_high;
}
if( (ras_line = malloc( (sizeof( int ) * pix_wid)+1)) == NULL ) return NO;
if( (savl = malloc( sizeof( char ) * pix_wid )) == NULL ) return NO;
pix_bwid = pix_wid / 8;
if( pix_wid & 7 ) pix_bwid += 1;
pix_size = (long)pix_bwid * pix_high;
if( pix_size < ((long)img_wid*img_high) ) pix_size = (long)img_wid*img_high;
if( pix_size > farcoreleft() ) return NO;
pix_buf = farmalloc( pix_size );
pix_base = fartol( pix_buf );
code_six = pix_base + (pix_size - ((long)img_wid*img_high));
return YES;
}
void mem_unset()
{
free( ras_line );
free( savl );
farfree( pix_buf );
}
char pbits[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
void setpbit( int color )
{
if( color ) {
*((char far *)ltofar( pix_base + (long)dot_row*(long)pix_bwid + (long)(dot_col>>3) )) |= pbits[dot_col & 7];
}
}
void pix_out( int code )
{
int pix_err, pe38;
if( (*rlp += intens[code]) > grey_level) {
setpbit( pix_white );
pix_err = *rlp - c_white;
}
else {
setpbit( pix_black );
pix_err = *rlp - c_black;
}
pe38 = (pix_err+pix_err+pix_err)>>3;
*rlp++ = pe38 + pix_diag;
pix_diag = pix_err>>2;
*rlp += pe38;
if( ++dot_col == pix_wid ) {
dot_col = 0;
rlp = ras_line;
dot_row += 1;
}
}
void sc_out( int code )
{
int i;
pix_out( code );
if( opt_t ) {
pix_out( code );
pix_out( code );
savl[savlix++] = code;
savl[savlix++] = code;
savl[savlix++] = code;
if( dot_col == 0 ) {
for( i=0; i!=savlix; i++ ) pix_out( savl[i] );
for( i=0; i!=savlix; i++ ) pix_out( savl[i] );
savlix = 0;
}
}
else {
if( opt_w ) pix_out( code );
if( opt_l ) {
savl[savlix++] = code;
if( opt_w ) savl[savlix++] = code;
if( dot_col == 0 ) {
for( i=0; i!=savlix; i++ ) pix_out( savl[i] );
savlix = 0;
}
}
}
}
void togrey()
{
unsigned long pixies, pixct, pixgix;
char far *cix;
int c;
msg_rc( 18, tab2, " Halftoning..." );
dot_row = dot_col = 0;
pixies = (long)img_wid * img_high;
pixgix = code_six;
for( pixct = 0l; pixct!=pixies; pixct++ ) {
cix = (char far *)ltofar( pixgix++ );
c = *cix;
*cix = 0;
sc_out( c );
if( !(pixct & 4095) ) sbar( (40l*pixct)/pixies );
}
}
void code_out( int code )
{
ngifcodes++;
if( ilace ) {
*((char far *)ltofar( code_six + (long)dot_row*img_wid + (long)dot_col )) = code;
if( ++dot_col == img_wid ) {
dot_col = 0;
if( (dot_row += i_leave) >= img_high ) {
switch( i_phase ) {
case 0: dot_row = 0;
break;
case 1: dot_row = 4;
i_phase++;
break;
case 2: dot_row = 2;
i_leave = 4;
i_phase++;
break;
case 3: dot_row = 1;
i_leave = 2;
break;
case 4: dot_row = 0;
i_leave = 1;
break;
}
}
}
} else sc_out( code );
}
void tran_out( int tran_code )
{
char *strix;
int i;
strix = str_buf;
i = 0;
do {
*strix++ = root_tab[tran_code].t_code;
i++;
tran_code = root_tab[tran_code].t_link;
} while( tran_code != -1 );
str_len = i;
strix--;
while( i-- ) code_out( *strix-- );
}
void procode( int cur_code )
{
mav_codes++;
if( tab_stor == 0 ) {
tab_stor = eoi_code+1;
tran_out( cur_code );
mav_length++;
}
else {
if( cur_code != tab_stor ) {
tran_out( cur_code );
mav_length += str_len;
if( str_len > max_pcr ) max_pcr = str_len;
}
else {
tran_out( old_code );
code_out( str_buf[str_len-1] );
mav_length += str_len+1;
if( (str_len+1) > max_pcr ) max_pcr = str_len+1;
}
root_tab[tab_stor].t_code = str_buf[str_len-1];
root_tab[tab_stor].t_link = old_code;
if( (tab_stor++) == cur_mask ) {
if( cur_mask != 4095 ) {
cur_mask += cur_mask+1;
cur_bits++;
}
}
}
old_code = cur_code;
}
void uncode()
{
int hi_bits;
unsigned long shreg;
int i, cur_code;
dot_row = 0;
rlp = ras_line;
dot_col = 0;
pix_diag = 0;
for( i=0; i!=img_wid; i++ ) ras_line[i] = -(rand() % 131)*fbits;
if( ilace ) msg_rc( 18, tab2," Unpacking..." );
else msg_rc( 18, tab2, "Unpacking and Halftoning..." );
set_mask();
shreg = gnxcic();
shreg |= gnxcic() << 8;
shreg |= (long) gnxcic() << 16;
hi_bits = 8;
do {
cur_code = shreg & cur_mask;
if( cur_code == eoi_code ) cur_bits = 0;
else {
i = cur_bits;
while( i-- ) {
shreg = shreg >> 1;
if( !(--hi_bits) ) {
shreg |= (long) gnxcic() << 16;
hi_bits = 8;
}
}
if( cur_code == clr_code ) set_mask();
else procode( cur_code );
}
} while( cur_bits );
setcsts();
}
void d_window( int max_row, unsigned long roff )
{
char far *scrix[4];
unsigned nb, nr, row;
scrix[0] = 0xb8000000;
scrix[1] = 0xba000000;
scrix[2] = 0xbc000000;
scrix[3] = 0xbe000000;
nb = ( pix_wid > 640 ) ? 640 : pix_wid;
if( nb & 7 ) nb += 8 - (nb & 7);
nb /= 8;
nr = ( pix_high > max_row ) ? max_row : pix_high;
row = 0;
do {
farmemcpy( scrix[row], ltofar( pix_base+roff ), nb );
scrix[row] += 80;
row = ++row & vid_mask;
roff += pix_bwid;
} while( --nr );
}
void display_it()
{
unsigned max_row;
unsigned long porgi, phighmax;
unsigned priteoff, pritemax;
int disp_done, c;
if( ilace ) togrey();
porgi = 0;
max_row = 400;
vid_mask = 3;
if( opt_c || (setvmode( 0x74 ) != 0x74) ) {
setvmode( 6 );
max_row = 200;
vid_mask = 1;
}
phighmax = (pix_high > max_row) ? (long) (((long)pix_high*pix_bwid - (long)max_row*pix_bwid)) : 0;
pritemax = (pix_wid > 640 ) ? (pix_wid - 640)/8 : 0;
priteoff = 0;
disp_done = NO;
do {
d_window( max_row, porgi );
while( (c = getkey()) == EOF );
if( c == 0 ) {
while( (c = getkey()) == EOF );
switch( c ) {
case 71:
porgi = (long)priteoff;
break;
case 72:
if( porgi != 0 ) porgi -= pix_bwid;
break;
case 80:
if( (porgi+pix_bwid) < phighmax ) porgi += pix_bwid;
break;
case 73:
if( porgi > (pix_bwid *10) ) porgi -= pix_bwid * 10;
else porgi = (long)priteoff;
break;
case 81:
if( (porgi+pix_bwid*10) < phighmax ) porgi += pix_bwid * 10;
break;
case 75:
if( priteoff ) {
priteoff--;
porgi--;
}
break;
case 77:
if( priteoff < pritemax ) {
priteoff++;
porgi++;
}
break;
case 115:
if( priteoff > 10 ) {
priteoff -= 10;
porgi -= 10l;
}
break;
case 116:
if( (priteoff+10) < pritemax ) {
priteoff += 10;
porgi += 10l;
}
break;
case 79:
porgi = phighmax + priteoff;
break;
case 117:
disp_done = YES;
break;
}
}
else {
switch( c ) {
case 0x03:
case 0x1b:
case 'q':
case 'Q': disp_done = YES;
break;
}
}
} while( !disp_done );
setvmode( 3 );
curson();
clrscrn();
}
void make_box()
{
char boxs[43];
int i;
boxs[0] = 201;
for( i=1; i!=41; boxs[i++] = 205 );
boxs[41] = 187;
boxs[42] = 0;
msg_rc( 20, 19, boxs );
boxs[0] = 200;
boxs[41] = 188;
msg_rc( 22, 19, boxs );
boxs[0] = 186;
for( i=1; i!=41; boxs[i++] = 176 );
boxs[41] = 186;
msg_rc( 21, 19, boxs );
}
void gif_image()
{
int iblkct;
img_left = mygetc() | (mygetc() << 8 );
msg_rc( 8, tab3, "Left boundary:" );
msg_rcn( 8, tab4, img_left );
img_top = mygetc() | (mygetc() << 8 );
msg_rc( 9, tab3, "Top boundary:" );
msg_rcn( 9, tab4, img_top );
img_wid = mygetc() | (mygetc() << 8);
msg_rc( 8, tab1, "Image width:" );
msg_rcn( 8, tab2, img_wid );
img_high = mygetc() | (mygetc() << 8);
msg_rc( 9, tab1, "Image height:" );
msg_rcn( 9, tab2, img_high );
img_cfg = mygetc();
ilace = NO;
if( img_cfg & 64 ) {
ilace = YES;
msg_rc( 10, tab1, "Interlaced image." );
i_leave = 8;
i_phase = 1;
}
else {
msg_rc( 10, tab1, "Noninterlaced image." );
i_leave = 1;
i_phase = 0;
}
if( img_cfg & 128 ) {
msg_rc( 10, tab3, "Local color map present." );
gif_cmap();
}
img_csz = mygetc();
msg_rc( 11, tab1, "Image code size:" );
msg_rcn( 11, tab2, img_csz );
make_box();
max_pcr = 0;
mav_code = 0;
mav_length = 0;
ngifrecs = 0;
ngifcodes = 0;
if( mem_setup() ) {
rooter();
uncode();
display_it();
mem_unset();
}
else printf( "\n\nNot enough memory to contain image!\n" );
}
void interrupt cancel()
{
setvmode( 3 );
curson();
clrscrn();
exit(0);
}
int parse_args( int argc, char *argv[] )
{
char *cx;
opt_w = opt_l = opt_c = NO;
if( argc == 2 ) return YES;
if( argc != 3 ) return NO;
cx = argv[1];
argv[1] = argv[2];
while( *cx ) {
if( *cx++ == '/' ) {
switch( *cx++ ) {
case 'w' :
case 'W' : opt_w = YES;
break;
case 'l' :
case 'L' : opt_l = YES;
break;
case 'r' :
case 'R' : pix_black = 1;
pix_white = 0;
break;
case 'd':
case 'D': opt_w = opt_l = YES;
break;
case 'c':
case 'C': opt_c = YES;
break;
case 't':
case 'T': opt_t = YES;
break;
default: return NO;
}
}
}
}
main( int argc, char *argv[] )
{
int gifdone, gc;
if( parse_args( argc, argv ) ) {
stpcpy( fname, argv[1] );
if( !stristr( fname, "." ) ) strcat( fname, ".gif" );
if( giffile = fopen( fname, "rb" ) ) {
giffilen = filelength( fileno( giffile ) );
clrscrn();
msg_rc( 2, 26, "tgif -- Two-tone GIF utility" );
msg_rc( 4, tab1, "File name:" );
msg_rc( 4, tab2, fname );
if( gifsig_ok() ) {
if( gifscd() ) {
cursoff();
setvect( 0x23, cancel );
gif_cmap();
gifdone = NO;
do {
switch( gc = mygetc() ) {
case '!': gif_ext();
break;
case ',': gif_image();
break;
case '\0': break;
case ';': gifdone = YES;
break;
default: printf( "\nInvalid command code: %x\n", gc );
gifdone = YES;
break;
}
} while( !gifdone );
} else printf( "\nInvalid screen descriptor.\n" );
} else printf( "\n%s not a GIF file.\n", fname );
} else printf( "\nCan't open file: %s\n", fname );
}
else {
printf( "\nUsage: tgif {/w} {/l} {/d} {/t} {/r} {/c} giffile\n" );
printf( "\nOptions: /w == widen image" );
printf( "\n /l == lengthen image" );
printf( "\n /d == double size" );
printf( "\n /t == triple size" );
printf( "\n /r == reverse video (for LCD screens)" );
printf( "\n /c == force CGA mode\n" );
printf( "\nExample: tgif/d/r picture" );
printf( "\n Would open picture.GIF and display a double size" );
printf( "\n image in reverse video.\n" );
}
}