/*
 *		GIF encoder	from pbm2gif.c		Copyright (C) Aug. 1993 K.Asayama
 *										Slightly modified by SHIMA
 */

#define OUTBUF_SIZE 254
#define TABLE_SIZE 4096

static unsigned char obuf[OUTBUF_SIZE];

static FILE *giffp;
static int obp;
static int CBL;
static int strp;
static int tblp;
static int bit;
static int byte;
static int CM;

int _table[TABLE_SIZE+1][2];

#define table (_table+1)

void write_gif_head(FILE *file, int width, int height)
{
	int byte_width;
	int	c;

	giffp = file;
	byte_width = (width+7)/8;
	c = byte_width * 8;

	/* 0-5 byte */
	strcpy(obuf,"GIF87a");
	obp = 6;

	/* 6-12 byte */
	obuf[obp++] = c&0xff;		/* width */
	obuf[obp++] = c>>8;
	obuf[obp++] = height&0xff;	/* height */
	obuf[obp++] = height>>8;
	obuf[obp++] = 0xf0;
	obuf[obp++] = 0;			/* back ground color */
	obuf[obp++] = 0;
	
	/* global color map */
	obuf[obp++] = 0xff;
	obuf[obp++] = 0xff;
	obuf[obp++] = 0xff;
	obuf[obp++] = 0x00;
	obuf[obp++] = 0x00;
	obuf[obp++] = 0x00;
	
	obuf[obp++] = 0x2c;
	obuf[obp++] = 0;
	obuf[obp++] = 0;
	obuf[obp++] = 0;
	obuf[obp++] = 0;
	memcpy(obuf+obp,obuf+6,4);
	obp+=4;
	obuf[obp++] = 0;
	obuf[obp++] = 2;			/* clear code */
	if (fwrite(obuf,obp,1,giffp) != 1) {
		fprintf( stderr, "Can't write the monochrome GIF file.\n");
		exit(1);
	}

	table[-1][0] = 0;
	table[-1][1] = 1;
	table[0][0] = table[0][1] = -1;
	table[1][0] = table[1][1] = -1;

	memset(obuf, 0, OUTBUF_SIZE);
	bit = byte = obp = 0;
	CBL = 3;
	strp = -1;
	tblp = 6;
	CM = 0x08;
	outputcode(4,3);
}

void gif_encode(unsigned char *ibuf, int width)
{
	int ibp = 0;
	int c;
	int imask = 0x80;
	
	while(ibp < width) {
		c = (ibuf[ibp]&imask) ? 1 : 0;
		if (table[strp][c] == -1) {
			outputcode(strp, CBL);
			/* output */
			if (tblp < TABLE_SIZE) {
				table[strp][c] = tblp;
				table[tblp][0] = table[tblp][1] = -1;
				if (tblp == CM) {
					CBL++;
					CM <<= 1;
				}
				tblp++;
			}
			else {
				outputcode(4, CBL);
				table[0][0] = table[0][1] = -1;
				table[1][0] = table[1][1] = -1;
				CBL = 3;
				CM = 0x08;
				tblp = 6;
			}
			strp = c;
		}
		else 
			strp = table[strp][c];
		imask >>= 1;
		if (imask == 0){
			imask = 0x80;
			ibp++;
		}
	}
}

void outputcode(int code,int bits)
{
	static int mask[] = {0xff,0x7f,0x3f,0x1f,0x0f,0x07,0x03,0x01};

	while (bits) {
		obuf[byte] |= ((code & mask[bit]) << bit);
		if (8-bit <= bits) {
			code >>= (8-bit);
			bits -= (8-bit);
			bit = 0;
			byte++;
			if (byte == OUTBUF_SIZE) {
				fputc(OUTBUF_SIZE,giffp);
				if( fwrite(obuf,OUTBUF_SIZE,1,giffp) != 1){
					fprintf( stderr, "Can't write the monochrome GIF file.\n");
					exit(1);
				}
				memset(obuf,0,OUTBUF_SIZE);
				byte = 0;
			}
		}
		else {
			bit += bits;
			bits = 0;
		}
	}
}

void end_gif_file(void)
{
	outputcode(strp,CBL);		/* output strp */
	outputcode(5,CBL);			/* output endcode */
	if (byte || bit) {
		fputc(byte+(bit?1:0),giffp);
		fwrite(obuf,byte+(bit?1:0),1,giffp);
	}
	fwrite("\0;",2,1,giffp);
}
