/****************************************************************************
gif.c - read and write gif images using libgif/libungif.
Distributed with Xplanet.
Copyright (C) 2002 Hari Nair <hari@alumni.caltech.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <gif_lib.h>
/*
A lot of this is based on the gif2rgb and rgb2gif codes in the libungif
distribution.
*/
int
read_gif(const char *filename, int *width, int *height, unsigned char **rgb)
{
int interlace_offset[] = { 0, 4, 2, 1 };
int interlace_jump[] = { 8, 8, 4, 2 };
GifColorType *colormap;
GifFileType *infile;
GifRecordType record_type;
GifRowType *buffer = NULL;
int i, j;
int color_index;
unsigned char *ptr = NULL;
infile = DGifOpenFileName(filename);
if (infile == NULL)
{
PrintGifError();
return(0);
}
do
{
if (DGifGetRecordType(infile, &record_type) == GIF_ERROR)
{
PrintGifError();
return(0);
}
switch (record_type)
{
case IMAGE_DESC_RECORD_TYPE:
if (DGifGetImageDesc(infile) == GIF_ERROR)
{
PrintGifError();
return(0);
}
*width = infile->Image.Width;
*height = infile->Image.Height;
buffer = malloc(*height * sizeof(GifRowType *));
if (buffer == NULL)
{
fprintf(stderr, "Can't allocate memory for GIF file.\n");
return(0);
}
for (i = 0; i < *height; i++)
{
buffer[i] = malloc(*width * sizeof(GifPixelType));
if (buffer[i] == NULL)
{
fprintf(stderr, "Can't allocate memory for GIF line.\n");
return(0);
}
}
if (infile->Image.Interlace)
{
for (i = 0; i < 4; i++)
for (j = interlace_offset[i]; j < *height;
j += interlace_jump[i])
DGifGetLine(infile, buffer[j], *width);
}
else
{
for (i = 0; i < *height; i++)
DGifGetLine(infile, buffer[i], *width);
}
break;
case EXTENSION_RECORD_TYPE:
{
/* Skip extension blocks */
int ext_code;
GifByteType *ext;
if (DGifGetExtension(infile, &ext_code, &ext) == GIF_ERROR)
{
PrintGifError();
return(0);
}
while (ext != NULL)
{
if (DGifGetExtensionNext(infile, &ext) == GIF_ERROR)
{
PrintGifError();
return(0);
}
}
}
break;
case TERMINATE_RECORD_TYPE:
break;
default:
fprintf(stderr, "unknown record type in GIF file\n");
break;
}
} while (record_type != TERMINATE_RECORD_TYPE);
colormap = (infile->Image.ColorMap ? infile->Image.ColorMap->Colors
: infile->SColorMap->Colors);
rgb[0] = malloc(3 * *width * *height);
if (rgb[0] == NULL)
{
fprintf(stderr, "Can't allocate memory for GIF file.\n");
return(0);
}
ptr = rgb[0];
for (j = 0; j < *height; j++)
{
for (i = 0; i < *width; i++)
{
color_index = (int) buffer[j][i];
*ptr++ = (unsigned char) colormap[color_index].Red;
*ptr++ = (unsigned char) colormap[color_index].Green;
*ptr++ = (unsigned char) colormap[color_index].Blue;
}
free(buffer[j]);
}
free(buffer);
DGifCloseFile(infile);
return(1);
}
int
write_gif(const char *filename, int width, int height, char *rgb)
{
int i;
int colormap_size = 256;
GifByteType *red, *green, *blue, *buffer, *ptr;
GifFileType *outfile;
ColorMapObject *colormap;
red = malloc(width * height * sizeof(GifByteType));
green = malloc(width * height * sizeof(GifByteType));
blue = malloc(width * height * sizeof(GifByteType));
buffer = malloc(width * height * sizeof(GifByteType));
if (red == NULL || green == NULL || blue == NULL || buffer == NULL)
{
fprintf(stderr, "Can't allocate memory for GIF file.\n");
return(0);
}
colormap = MakeMapObject(colormap_size, NULL);
for (i = 0; i < width * height; i++)
{
red[i] = (GifByteType) rgb[3*i ];
green[i] = (GifByteType) rgb[3*i+1];
blue[i] = (GifByteType) rgb[3*i+2];
}
if (QuantizeBuffer(width, height, &colormap_size, red, green, blue,
buffer, colormap->Colors) == GIF_ERROR)
{
PrintGifError();
return(0);
}
free(red);
free(green);
free(blue);
outfile = EGifOpenFileName((char *) filename, FALSE);
if (outfile == NULL)
{
PrintGifError();
return(0);
}
if (EGifPutScreenDesc(outfile, width, height, colormap_size, 0, colormap)
== GIF_ERROR)
{
PrintGifError();
return(0);
}
if (EGifPutImageDesc(outfile, 0, 0, width, height, FALSE, NULL)
== GIF_ERROR)
{
PrintGifError();
return(0);
}
ptr = buffer;
for (i = 0; i < height; i++)
{
if (EGifPutLine(outfile, ptr, width) == GIF_ERROR)
{
PrintGifError();
return(0);
}
ptr += width;
}
EGifSpew(outfile);
if (EGifCloseFile(outfile) == GIF_ERROR)
PrintGifError();
free(buffer);
return(1);
}
syntax highlighted by Code2HTML, v. 0.9.1