/* gif.c:
 *
 * adapted from code by kirk johnson (tuna@athena.mit.edu).  most of this
 * code is unchanged. -- jim frost 12.31.89
 *
 * gifin.c
 * kirk johnson
 * november 1989
 *
 * routines for reading GIF files
 *
 * Copyright 1989 Kirk L. Johnson (see the included file
 * "kljcpyrght.h" for complete copyright information)
 */

#ifdef USE_GIF

#include "image.h"
#include <gif_lib.h>

static void
tellAboutImage(name, gifp)
	char *name;
	GifFileType *gifp;
{
	fprintf(stderr, "%s is a %dx%d GIF image\n",
	    name, gifp->SWidth, gifp->SHeight);
}

/* The way Interlaced image should. */
static int InterlacedOffset[] = { 0, 4, 2, 1 };
/* be read - offsets and jumps... */
static int InterlacedJumps[] = { 8, 8, 4, 2 };

Image *
gifLoad(fullname, name, verbose)
	char *fullname, *name;
	unsigned int verbose;
{
	byte *pixline;
	unsigned char *Buffer, *BufferP;
	Image *image;
	int Size, Row, Col, Width, Height, Count, ExtCode;
	int i, j, x, y, trans = 0;
	GifRecordType RecordType;
	GifByteType *Extension;
	GifRowType *ScreenBuffer;
	GifRowType GifRow;
	GifFileType *GifFile;
	ColorMapObject *ColorMap;
	GifColorType *ColorMapEntry;

	GifFile = DGifOpenFileName(fullname);
	if (GifFile == NULL)
		return NULL;

	if ((ScreenBuffer = (GifRowType *)
	    malloc(GifFile->SHeight * sizeof(GifRowType *))) == NULL) {
		fprintf(stderr, "malloc failed\n");
		exit(1);
	}

	/* Size in bytes one row.*/
	Size = GifFile->SWidth * sizeof(GifPixelType);
	/* First row. */
	if ((ScreenBuffer[0] = (GifRowType) malloc(Size)) == NULL) {
		fprintf(stderr, "malloc failed\n");
		exit(1);
	}

	/* Set its color to BackGround. */
	for (i = 0; i < GifFile->SWidth; i++)
		ScreenBuffer[0][i] = GifFile->SBackGroundColor;
	for (i = 1; i < GifFile->SHeight; i++) {
		/*
		 * Allocate the other rows, and set their color to background
		 * too:
		 */
		if ((ScreenBuffer[i] = (GifRowType) malloc(Size)) == NULL) {
			fprintf(stderr, "malloc failed\n");
			exit(1);
		}

		memcpy(ScreenBuffer[i], ScreenBuffer[0], Size);
	}

	/* Scan the content of the GIF file and load the image(s) in: */
	do {
		if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
			PrintGifError();
			exit(-1);
		}
		switch (RecordType) {
		case IMAGE_DESC_RECORD_TYPE:
			if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
				PrintGifError();
				exit(-1);
			}
			Row = GifFile->Image.Top; /* Image Position relative to Screen. */
			Col = GifFile->Image.Left;
			Width = GifFile->Image.Width;
			Height = GifFile->Image.Height;
			if (GifFile->Image.Left + GifFile->Image.Width > GifFile->SWidth ||
			   GifFile->Image.Top + GifFile->Image.Height > GifFile->SHeight) {
				fprintf(stderr,
"Image %d is not confined to screen dimension, aborted.\n");
				exit(-2);
			}
			if (GifFile->Image.Interlace) {
				/* Need to perform 4 passes on the images: */
				for (Count = i = 0; i < 4; i++)
					for (j = Row + InterlacedOffset[i]; j < Row + Height;
							     j += InterlacedJumps[i]) {
					if (DGifGetLine(GifFile, &ScreenBuffer[j][Col],
					    Width) == GIF_ERROR) {
					    PrintGifError();
					    exit(-1);
					}
				}
			}
			else {
				for (i = 0; i < Height; i++) {
					if (DGifGetLine(GifFile, &ScreenBuffer[Row++][Col],
					    Width) == GIF_ERROR) {
						PrintGifError();
						exit(-1);
					}
				}
			}
			break;
		case EXTENSION_RECORD_TYPE:
			/* Skip any extension blocks in file: */
			if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
				PrintGifError();
				exit(-1);
			}
			/* very adhoc transparency support */
			if (ExtCode == GRAPHICS_EXT_FUNC_CODE){
				if (*((char *)Extension +1) & 1)
					trans = 1;
			}
			while (Extension != NULL) {
				if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
					PrintGifError();
					exit(-1);
				}
			}
			break;
		case TERMINATE_RECORD_TYPE:
			break;
		default: /* Should be traps by DGifGetRecordType. */
			break;
		}
	} while (RecordType != TERMINATE_RECORD_TYPE);

	/* Lets dump it - set the global variables required and do it: */
	ColorMap = (GifFile->Image.ColorMap
		? GifFile->Image.ColorMap
		: GifFile->SColorMap);

	image = newRGBImage(GifFile->SWidth, GifFile->SHeight, 8);

	if (trans)
		image->trans = GifFile->SBackGroundColor;
	else
		image->trans = -1;
	image->rgb.used = ColorMap->ColorCount;
	for (i = 0; i < ColorMap->ColorCount; i++) {
		ColorMapEntry = &ColorMap->Colors[i];
		image->rgb.red[i]= ColorMapEntry->Red << 8;
		image->rgb.green[i]= ColorMapEntry->Green << 8;
		image->rgb.blue[i]= ColorMapEntry->Blue << 8;
	}

	for (y = 0; y < GifFile->SHeight; y++) {
		GifRow = ScreenBuffer[y];
		pixline = image->data + (y * image->width * image->pixlen);
		for (x = 0; x < GifFile->SWidth; x++)
			pixline[x] = GifRow[x];
	}

	if (DGifCloseFile(GifFile) == GIF_ERROR) {
		PrintGifError();
		exit(-1);
	}

	image->title = dupString(name);

	return image;
}

int
gifIdent(fullname, name)
	char *fullname, *name;
{
	GifFileType *gifp;
	int ret;

	gifp = DGifOpenFileName(fullname);
	if (gifp == NULL)
		ret = 0;
	else {
		DGifCloseFile(gifp);
		tellAboutImage(name);
		ret = 1;
	}
	return ret;
}
#endif /*USE_GIF*/
