Here's a code snippet that will save a block of memory to disk as a
Gif compressed image. You must provide a pointer to the block of memory
and an optional pointer to the associated color palette as a series of
256 8 bit RGB values. If no color palette is specified then the image is
assumed to be grayscale.
That's all there is to it.
John W. Ratcliff
jratcliff@verant.com
//*******************************************************************
//** Begin SGIF.H header file.
//*******************************************************************
#ifndef SGIF_H
#define SGIF_H
class SGif
{
public:
static int SaveGif(const char *filename, // filename to save as.
int wid, // width of image
int hit, // height of image
const unsigned char *image, // image data
const unsigned char *pal=0); // color palette 256 3 byte RGB tuples
// If no color palette assigned, then grayscale
// is assumed.
};
#endif
//*******************************************************************
//** Begin SGIF.CPP
//*******************************************************************
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "sgif.h"
static void initialize(void);
static struct
{
char name[3];
char version[3];
short xres, yres;
unsigned short packed;
char back_col_index;
char aspect_ratio;
} gif_header;
static void write_code(unsigned short code);
static FILE *fsave;
static short clear, codebits, colors, end, length, lastentry,
nbits, nbytes, entries, actual,
startbits, xres, yres;
static unsigned char buffer[16384],block[266],test[100];
static unsigned short hashcode, next, str_index[5003];
int SGif::SaveGif(const char *filename,
int wid,
int hit,
const unsigned char *image,
const unsigned char *cpal)
{
short i, row, col, color,temp;
unsigned short hashentry;
unsigned char bits;
unsigned char pal[768];
if ( cpal ) // if color palette specified, copy it
{
memcpy(pal,cpal,768);
}
else
{
// Set up default grayscale color palette.
for (int i=0; i<256; i++)
{
pal[i*3+0] = i;
pal[i*3+1] = i;
pal[i*3+2] = i;
}
}
xres = (short) wid;
yres = (short) hit;
fsave = fopen(filename, "wb");
if ( fsave== NULL )
{
return 0;
}
strcpy(gif_header.name,"GIF");
strcpy(gif_header.version, "87a");
gif_header.xres = (short) wid;
gif_header.yres = (short) hit;
gif_header.packed = 0xF7;
bits = 8;
colors = 256;
gif_header.back_col_index = 0;
gif_header.aspect_ratio = 0;
fwrite(&gif_header,1,13,fsave);
fwrite(pal,1,768,fsave);
fputc(',',fsave);
fputc(0,fsave);
fputc(0,fsave);
fputc(0,fsave);
fputc(0,fsave);
fwrite(&xres,1,2,fsave);
fwrite(&yres,1,2,fsave);
fputc(0,fsave);
startbits = bits+1;
clear = 1 << (startbits - 1);
end = clear+1;
fputc(bits,fsave);
codebits = startbits;
nbytes = 0;
nbits = 0;
for (i = 0; i < 266; i++)
block[i] = 0;
initialize();
for (row = 0; row < yres; row++)
{
for (col = 0; col < xres; col++)
{
color = (short) *image++;
test[0] = (unsigned char) ++length;
test[length] = (unsigned char) color;
switch(length)
{
case 1:
lastentry = color;
break;
case 2:
hashcode = 301 * (test[1]+1);
default:
hashcode *= (color + length);
hashentry = ++hashcode % 5003;
for( i = 0; i < 5003; i++)
{
hashentry = (hashentry + 1) % 5003;
if (memcmp(&buffer[str_index[hashentry]+2],
test,length+1) == 0)
break;
if (str_index[hashentry] == 0)
i = 5003;
}
if (str_index[hashentry] != 0 && length < 97)
{
memcpy(&lastentry,&buffer[str_index[hashentry]],2);
break;
}
write_code(lastentry);
entries++;
if (str_index[hashentry] == 0)
{
temp = entries+end;
str_index[hashentry] = next;
memcpy(&buffer[next],&temp,2);
memcpy(&buffer[next+2],test,length+1);
next += length+3;
actual++;
}
test[0] = 1;
test[1] = (unsigned char) color;
length = 1;
lastentry = color;
if ((entries+end) == (1<<codebits))
codebits++;
if ( entries + end > 4093 || actual > 3335
|| next > 15379)
{
write_code(lastentry);
initialize();
}
}
}
}
write_code(lastentry);
write_code(end);
fputc(0,fsave);
fputc(';',fsave);
fclose(fsave);
return(1);
}
void initialize(void)
{
write_code(clear);
entries = 0;
actual = 0;
next = 1;
length = 0;
codebits = startbits;
buffer[0] = 0;
memset(str_index,0x00,10006);
}
void write_code(unsigned short code)
{
block[nbytes ] |= ((code << nbits) & 0xFF);
block[nbytes+1] |= ((code >> (8 - nbits)) & 0xFF);
block[nbytes+2] |= (((code>>(8 - nbits)) >> 8) & 0xFF);
nbits += codebits;
while (nbits >= 8)
{
nbits -= 8;
nbytes++;
}
if (nbytes < 251 && code != end) return;
if (code == end)
{
while (nbits > 0)
{
nbits -= 8;
nbytes++;
}
}
fputc(nbytes,fsave);
fwrite(block,nbytes,1,fsave);
memcpy(block,&block[nbytes],5);
memset(&block[5],0x00,260);
nbytes = 0;
}
//*******************************************************************
//** Test application demonstrating usage of the Sgif utility
//*******************************************************************
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "sgif.h"
void main(int argc,char **argv)
{
// gif saving test program.
int wid = 256;
int hit = 256;
unsigned char *image = new unsigned char[wid*hit];
for (int y=0; y<hit; y++)
{
memset( &image[y*wid], y, wid); // build gradient
}
printf("Saving test1.gif\n");
SGif::SaveGif("test1.gif",wid,hit,image);
// now create a test color palette.
unsigned char pal[768];
for (int i=0; i<256; i++)
{
pal[i*3+0] = i; // set red component.
pal[i*3+1] = i/2; // set green component.
pal[i*3+2] = i/4; // set blue component.
}
printf("Saving test2.gif\n");
SGif::SaveGif("test2.gif",wid,hit,image,pal);
delete image;
}
|