/*----------------------------------------------------------------------*/
/* Copyright (c) 1988-1989						*/
/* by CompuServe Inc., Tucson, AZ.  All Rights Reserved			*/
/* GIFTIF.C can be copied and distributed freely for any		*/
/* non-commercial purposes. GIFTIF.C can only be incorporated		*/
/* into commercial software with the permission of CompuServe Inc.	*/
/*----------------------------------------------------------------------*/

/* GIFTIF.C */

/*
 * ABSTRACT:
 *	This file contains main program to convert GIF files into
 *	one-dimensional group-3 FAX compressed files.
 *
 * AUTHOR: Doug Chinnock
 *
 * REVISION HISTORY:
 *
 */

#include        <stdio.h>
#include	<string.h>
#include	<dos.h>

#include	"GIFbase.h"
#include	"cnvhuf.h"
#include	"rletif.h"
#include	"writetif.h"
#include	"readgif.h"
#include	"gifreade.h"
#include	"expander.h"

extern	int	scan_lines; 

/* Define all the prototypes */

#include	"writetif.h"

short int	write_TIF_pixel( unsigned char	TIF_pixel );

void	add_TIF_tag(	short int	TT_tag_code,
			short int	TT_value_type,
			long int	TT_value_count,
			short int	TT_value1,
			short int	TT_value2
		   );

/* Top scope variables and constants: */

static rle_line
    TIF_cur_line;

static IFD_header
    * IFD_body;

static struct
    {
    short int
	entry_idx;			/* Entry with offset values */
    short int
	entry_offset;			/* Values loc in ifd_offset_params */
					/* Or -1 if not yet determined */
    } ifd_offset_entries[5];

static unsigned char
    ifd_offset_params[250];		/* Place to accum oversize parameters */

static short int
    ifd_offsets_count,			/* Number of ifd_offset_entries */
    ifd_offset_free,			/* 1st free byte in ifd_offset_params */
    ifd_offsets_begin,			/* 1st byte in file for offset values */
    ifd_offsets_end,			/* Last byte in file for offset values */
    OBJ_screen_width,			/* Length of lines to use to make TIF */
    tot_lines;				/* Count of lines compressed */

static unsigned
	scaling;

short int	write_TIF_pixel( unsigned char	TIF_pixel )
{
colors
    BW_pixel;

unsigned
    scale_count;

if ( TIF_pixel == 0 )
    BW_pixel = WHITE;
else
    BW_pixel = BLACK;

for (scale_count = scaling; scale_count > 0; scale_count --)
    {
    TIF_cur_line.current_column ++;

    if ( TIF_cur_line.rle_pointer < LONGEST_RLE )
	{				/* Buffer not full yet */
	if ( BW_pixel == TIF_cur_line.rle_color )
	    {				/* More of same color */
	    TIF_cur_line.rle_list[TIF_cur_line.rle_pointer] ++;
	    }
	else
	    {				/* Color change */
	    TIF_cur_line.rle_color = BW_pixel;
	    TIF_cur_line.rle_pointer ++;
	    TIF_cur_line.rle_list[TIF_cur_line.rle_pointer] = 1;
	    };
	}
    else
	{				/* Buffer overflowed */
	return -1;
	}
    }

if ( TIF_cur_line.current_column >= OBJ_screen_width )
    {				/* Line full now */
    while (TIF_cur_line.current_column < FAX_line_width )
	{
	if ( TIF_cur_line.rle_color != WHITE )
	    {
	    TIF_cur_line.rle_color = WHITE;
	    TIF_cur_line.rle_pointer ++;
	    TIF_cur_line.rle_list[TIF_cur_line.rle_pointer] = 1;
	    }
	else
	    {
	    TIF_cur_line.rle_list[TIF_cur_line.rle_pointer] ++;
	    }

	TIF_cur_line.current_column ++;
	} /* while (TIF_cur_line.current_column < FAX_line_screen_width ) */

    TIF_cur_line.rle_pointer ++;	/* Count the run */
    TIF_cur_line.line_length = TIF_cur_line.current_column;
    TIF_cur_line.rle_count = TIF_cur_line.rle_pointer;

for (scale_count = scaling; scale_count > 0; scale_count --)
    compress_huffman_line( &TIF_cur_line );

    /* Start new line */

    TIF_cur_line.current_column = 0;
    TIF_cur_line.rle_color = 0;
    TIF_cur_line.rle_pointer = 0;
    TIF_cur_line.rle_list[TIF_cur_line.rle_pointer] = 0;
    };

return 0;
} /* write_TIF_pixel */

void	add_TIF_tag(	short int	TT_tag_code,
			short int	TT_value_type,
			long int	TT_value_count,
			short int	TT_value1,
			short int	TT_value2
		   )
{
	(*IFD_body).IFD_tag_element[(*IFD_body).IFD_ele_cnt].
				IFD_tag = TT_tag_code,
		(*IFD_body).IFD_tag_element[(*IFD_body).IFD_ele_cnt].
				IFD_type = TT_value_type;
		(*IFD_body).IFD_tag_element[(*IFD_body).IFD_ele_cnt].
				IFD_length = TT_value_count;
		switch ( TT_value_type )
		    {
		    case 3 :		/* 16 bit unsigned integer(s) */
			(*IFD_body).IFD_tag_element[(*IFD_body).IFD_ele_cnt].
					params.short_pair[0] = TT_value1;
			(*IFD_body).IFD_tag_element[(*IFD_body).IFD_ele_cnt].
					params.short_pair[1] = TT_value2;
			break;
		    case 4 :		/* 32 bit unsigned integer(s) */
			(*IFD_body).IFD_tag_element[(*IFD_body).IFD_ele_cnt].
					params.long_one = (long)TT_value1;
			break;
		    case 5 :		/* fraction(2) of 2 32 bit integers */
			ifd_offset_entries[ifd_offsets_count].entry_idx =
							(*IFD_body).IFD_ele_cnt;
			ifd_offset_entries[ifd_offsets_count ++].entry_offset =
							ifd_offset_free;
			ifd_offset_params[ifd_offset_free ++] = (unsigned char)(
					(long)(TT_value1) & 0xFF );
			ifd_offset_params[ifd_offset_free ++] = (unsigned char)(
					( (long)(TT_value1) >> 8 ) & 0xFF );
			ifd_offset_params[ifd_offset_free ++] = (unsigned char)(
					( (long)(TT_value1) >> 16 ) & 0xFF );
			ifd_offset_params[ifd_offset_free ++] = (unsigned char)(
					(long)(TT_value1) >> 24 );
			ifd_offset_params[ifd_offset_free ++] = (unsigned char)(
					(long)(TT_value2) & 0xFF );
			ifd_offset_params[ifd_offset_free ++] = (unsigned char)(
					( (long)(TT_value2) >> 8 ) & 0xFF );
			ifd_offset_params[ifd_offset_free ++] = (unsigned char)(
					( (long)(TT_value2) >> 16 ) & 0xFF );
			ifd_offset_params[ifd_offset_free ++] = (unsigned char)(
					(long)(TT_value2) >> 24 );
			break;
		    case 1 :		/* 8 bit unsigned integer(s) */
		    case 2 :		/* ASCIZ string */
		    default :
			printf( "\nTIF type not supported yet\n" );
			break;
		    }; /* switch ( IFD_type ) */

		(*IFD_body).IFD_ele_cnt ++;

} /* add_TIF_tag */

void main (void)
{
   char
	LetterAnswer[2],
	input_name[25],
	output_name[25];
   unsigned
	done;
   short
	GIF_screen_width,
	GIF_screen_height,
	GIF_color_res,
	GIF_fill_color,
	GIF_default_color_cnt,
	GIF_left_edge,
	GIF_top_edge,
	GIF_width,
	GIF_height,
	GIF_interlaced,
	GIF_img_color_cnt,
	i,
	status;

    static struct ColorEntry
	GIF_default_map[MaxColors],
	GIF_img_map[MaxColors];

    static union
	{			/* Buffer to hold whole TIF header */
	TIF_header	TIF_member;
	char		TIF_buffer[sizeof(TIF_header)+sizeof(IFD_header)];
	}	TIF_work_bfr;

    static char
	TIF_sign_contents[4] = TIF_sign_par;

    /* Access and prepare the GIF file */

    do
	{
	printf( "\nGIF source file: " );
	scanf( "%25s", input_name );
	}
    while ( init_GIF_input(input_name) != 0 );

    status = ReadScreenDesc(
    			   next_GIF_byte,
			 & GIF_screen_width,
			 & GIF_screen_height,
			 & GIF_color_res,
			 & GIF_fill_color,
			 & GIF_default_color_cnt,
			   GIF_default_map,
			   MaxColors
			);
    if ( status == 0 )
	{			/* GIF data set not acceptable */
	printf( "\nGIF file not acceptable for conversion\n" );
	return;
	};

    printf( "GIF file has %d lines %d pixels long\n Is scaling wanted? ",
		GIF_screen_height,
		GIF_screen_width );
    scanf( "%1s", LetterAnswer );

    if ( LetterAnswer[0] == 'Y' || LetterAnswer[0] == 'y' )
	{
	scaling = 0;
	while ( scaling == 0
		||  GIF_screen_width*scaling > FAX_line_width )
	    {
	    printf( "   Desired enlargement multiplier: ");
	    scanf( "%u", &scaling );
	    }
	}
    else
	{
	scaling = 1;
	}

    OBJ_screen_width = GIF_screen_width * scaling;

    /* Activate the TIF file builder */

    printf( "TIF product file: " );
    scanf( "%25s", output_name );
    init_TIF_output(output_name);

    tot_lines = 0;
    done = 0;

    while (! done)
	{
	switch ( next_GIF_byte() )	/* Get character after header */
	    {
	    case ',' :			/* Start of image */
		if (! ReadImageDesc( next_GIF_byte,
				     & GIF_left_edge,
				     & GIF_top_edge,
				     & GIF_width,
				     & GIF_height,
				     & GIF_interlaced,
				     & GIF_img_color_cnt,
				       GIF_img_map,
				       MaxColors ) )
		    {
		    printf( "\nGIF file not acceptable for conversion\n" );
		    return;
		    };

		/* Test compatibility */

		if ( GIF_interlaced )
		    {
		    printf( "\nCannot handle interlaced GIF\n" );
		    return;
		    };

		/* Create TIF header */

		for (i = 0; i < 4; i ++ )
		    TIF_work_bfr.TIF_member.TIF_sign[i] = TIF_sign_contents[i];
		TIF_work_bfr.TIF_member.IFD_offset = sizeof(TIF_header);

		IFD_body = (IFD_header *)(&TIF_work_bfr);
		FP_OFF(IFD_body) += sizeof(TIF_header);
		(*IFD_body).IFD_ele_cnt = 0;

		ifd_offsets_count = 0;
		ifd_offset_free = 0;

		/* Following must be in ascending order by IFD_tag field */

		add_TIF_tag( TT_width, TT_width_type, TT_width_cnt, 1728, 0 );
		add_TIF_tag( TT_length, TT_length_type, TT_length_cnt,
			     GIF_height, 0 );
		add_TIF_tag( TT_PixBits, TT_PixBits_type, TT_PixBits_cnt,
			     TT_PixBits_par, 0 );
		add_TIF_tag( TT_Cmprs, TT_Cmprs_type, TT_Cmprs_cnt,
			     TT_Cmprs_par, 0 );
		add_TIF_tag( TT_Revrs, TT_Revrs_type, TT_Revrs_cnt,
			     TT_Revrs_par, 0 );
		add_TIF_tag( TT_MSBend, TT_MSBend_type, TT_MSBend_cnt,
			     TT_MSBend_par, 0 );

		(*IFD_body).IFD_tag_element[(*IFD_body).IFD_ele_cnt].
				IFD_tag = TT_Image;
		(*IFD_body).IFD_tag_element[(*IFD_body).IFD_ele_cnt].
				IFD_type = TT_Image_type;
		(*IFD_body).IFD_tag_element[(*IFD_body).IFD_ele_cnt].
				IFD_length = 1;
		ifd_offset_entries[ifd_offsets_count].entry_idx =
							(*IFD_body).IFD_ele_cnt;
		ifd_offset_entries[ifd_offsets_count ++].entry_offset = -1;
		(*IFD_body).IFD_ele_cnt ++;

		add_TIF_tag( TT_Orient, TT_Orient_type, TT_Orient_cnt,
			     TT_Orient_par, 0 );
		add_TIF_tag( TT_Samps, TT_Samps_type, TT_Samps_cnt,
			     TT_Samps_par, 0 );
		add_TIF_tag( TT_X_dense, TT_X_dense_type, TT_X_dense_cnt,
			     TT_X_dense_par1, TT_X_dense_par2 );
		add_TIF_tag( TT_Y_dense, TT_Y_dense_type, TT_Y_dense_cnt,
			     TT_Y_dense_par1, TT_Y_dense_par2 );
		add_TIF_tag( TT_Grp3Opt, TT_Grp3Opt_type, TT_Grp3Opt_cnt,
			      TT_Grp3Opt_par, 0 );
		add_TIF_tag( TT_Resol, TT_Resol_type, TT_Resol_cnt,
			     TT_Resol_par, 0 );
		add_TIF_tag( TT_PagNum, TT_PagNum_type, TT_PagNum_cnt,
			     TT_PagNum_par1, TT_PagNum_par2 );

		ifd_offsets_begin = sizeof(TIF_header) + sizeof(short int)
			 + sizeof(IFD_tag_body) * (*IFD_body).IFD_ele_cnt + 4;
		ifd_offsets_end = ifd_offsets_begin + ifd_offset_free;

		/* Insert offset pointers into header just build */

		for ( i = 0; i < ifd_offsets_count; i ++ )
		    {
		    if ( ifd_offset_entries[i].entry_offset >= 0 )
			(*IFD_body)
			.IFD_tag_element[ ifd_offset_entries[i].entry_idx ]
			.params.offset = ifd_offsets_begin
			               + ifd_offset_entries[i].entry_offset;
		    else
			(*IFD_body)
			.IFD_tag_element[ ifd_offset_entries[i].entry_idx ]
			.params.offset = ifd_offsets_end;
		    };

		/* Write out the header */

		for ( i = 0; i < ifd_offsets_begin - 4; i ++ )
		    put_TIF_byte( TIF_work_bfr.TIF_buffer[ i ] );

		/* Write out the link to the next IFD */

		for ( i = 0; i < 4; i ++ )
		    put_TIF_byte( 0 );		/* NULL */

		/* Write out the indirect parameters */

		for ( i = 0; i < ifd_offset_free; i ++ )
		    put_TIF_byte( ifd_offset_params[ i ] );

		/* Setup for conversion of GIF to TIF images */

		TIF_cur_line.current_column = 0;
		TIF_cur_line.rle_pointer = 0;
		TIF_cur_line.rle_list[TIF_cur_line.rle_pointer] = 0;

		/* Perform the conversion */

		status = Expand_Data( next_GIF_byte,
				      write_TIF_pixel );

		if ( status != 0 )
		    {
		    printf( "\nGIF file not acceptable for conversion\n" );
		    return;
		    };

		for ( i = 0; i < 6; i ++ )
		    TIF_write_bits( 12, 0x1);	/* Write end of page code */

		break;

	    case ';' :			/* End of dataset */
		done = 1;
		break;

	    case '!' :			/* undefined extension */
		printf( "\nGIF file not acceptable for conversion\n" );
		return;

	    default :			/* Unknown delimiter */
		printf( "\nGIF file not acceptable for conversion\n" );
		return;

	    } /* switch */
	} /* while (! done) */

   close_stream( );
   finish_output( );
}
