#ifndef __GIF_WRAPPER_H__
#define __GIF_WRAPPER_H__
//基于giflib的c++对象封装
#include "gif_lib.h"
#include "rectimage.h"
#include <vector>
using namespace std;
class CGifImage
{
public:
CGifImage();
~CGifImage();
bool open(const char* gif_path);
void close();
const vector<RECT_IMAGE*>& getFrames() const { return frameArray ;};
private:
void dumpCurrentFrame();
GifFileType *mpGifFile;// gif文件句柄
GifRowType *mpScreenBuffer;//GifRowType 实际是一个char* 类型;ScreenBuffer[0]表示指向第0行的像素列表的指针,ScreenBuffer[0][2]表示第0行第2个像素
vector<RECT_IMAGE*> frameArray;
ColorMapObject *ColorMap;
};
/*
测试例子:看 cpp文件里的main
*/
#endif//__GIF_WRAPPER_H__

//   g++ gif_wrapper.cpp -o testgif -L./lib -lgif -I./lib -I./
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
#include <fcntl.h>
#include "gif_wrapper.h"
CGifImage::CGifImage():mpGifFile(NULL),mpScreenBuffer(NULL),ColorMap(NULL)
{
}
CGifImage::~CGifImage()
{
close();
}
void CGifImage::close()
{
if (NULL != mpScreenBuffer)
{
(void)free(mpScreenBuffer);
mpScreenBuffer=NULL;
}
if (NULL != mpGifFile)
{
int Error=0;
DGifCloseFile(mpGifFile);
mpGifFile=NULL;
}
int count = frameArray.size();
for (int i=0 ;i < count;++i)
{
RECT_IMAGE* p = frameArray[i];
if (NULL != p)
{
delete p;
p = NULL;
}
}
frameArray.clear() ;
}
void  CGifImage::dumpCurrentFrame()
{
RECT_IMAGE*  rectImage = new RECT_IMAGE();
if (NULL == rectImage)
{
return ;
}
rectImage->init( mpGifFile->SWidth,mpGifFile->SHeight ,NULL);
GifRowType GifRow;
GifColorType *ColorMapEntry;
for (int i = 0; i < mpGifFile->SHeight; i++)
{
GifRow = mpScreenBuffer[i];
for (int j = 0; j < mpGifFile->SWidth; j++)
{
ColorMapEntry = &ColorMap->Colors[GifRow[j]];
rectImage->putPixel(j,i, __RGB(ColorMapEntry->Red,ColorMapEntry->Green,ColorMapEntry->Blue));
}
}
frameArray.push_back(rectImage);
}
bool CGifImage::open( const char* gif_path )
{
GifFileType *GifFile=NULL;
GifRowType * ScreenBuffer=NULL;
if (NULL != mpGifFile)
{
close();
}
int i, j, Size, Row, Col, Width, Height, ExtCode, Count,Error;
GifRecordType RecordType;
GifByteType *Extension;
int ImageNum = 0;
int InterlacedOffset[] = { 0, 4, 2, 1 };  /* The way Interlaced image should. */
int InterlacedJumps[] = { 8, 8, 4, 2 };    /* be read - offsets and jumps... */
if ((GifFile = DGifOpenFileName(gif_path)) == NULL)
{
close();
return false;
}
//printf("GifFile->ImageCount : %d  GifFile->Image.Interlace:%d\n",GifFile->ImageCount,GifFile->Image.Interlace);
////* 
////* * Allocate the screen as vector of column of rows. Note this
////* * screen is device independent - it's the screen defined by the
////* * GIF file parameters.
////* */
if ((ScreenBuffer = (GifRowType *)malloc(GifFile->SHeight * sizeof(GifRowType))) == NULL)
{
//GIF_EXIT("Failed to allocate memory required, aborted.");
close();
return false;
}
Size = GifFile->SWidth * sizeof(GifPixelType);/* Size in bytes one row.*/
if ((ScreenBuffer[0] = (GifRowType) malloc(Size)) == NULL) /* First row. */
{
//GIF_EXIT("Failed to allocate memory required, aborted.");
close();
return false;
}
for (i = 0; i < GifFile->SWidth; i++)  /* Set its color to BackGround. */
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)
{
//GIF_EXIT("Failed to allocate memory required, aborted.");
close();
return false;
}
memcpy(ScreenBuffer[i], ScreenBuffer[0], Size);
}
//////* Scan the content of the GIF file and load the image(s) in: */
mpGifFile=GifFile;
mpScreenBuffer=ScreenBuffer;
ColorMap = (mpGifFile->Image.ColorMap? mpGifFile->Image.ColorMap: mpGifFile->SColorMap);
if (NULL == ColorMap)
{
close();
return false;
}
do 
{
if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) 
{
//PrintGifError(GifFile->Error);
//exit(EXIT_FAILURE);
close();
return false;
}
switch (RecordType) 
{
case IMAGE_DESC_RECORD_TYPE:
if (DGifGetImageDesc(GifFile) == GIF_ERROR) 
{
//PrintGifError(GifFile->Error);
//exit(EXIT_FAILURE);
close();
return false;
}
Row = GifFile->Image.Top; /* Image Position relative to Screen. */
Col = GifFile->Image.Left;
Width = GifFile->Image.Width;
Height = GifFile->Image.Height;
//printf("\n%s: Image %d at (%d, %d) [%dx%d]:     ", "record ", count, Col, Row, Width, 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",ImageNum);
//exit(EXIT_FAILURE);
close();
return false;
}
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]) 
{
//GifQprintf("\b\b\b\b%-4d", Count++);
if (DGifGetLine(GifFile, &ScreenBuffer[j][Col],Width) == GIF_ERROR)
{
//PrintGifError(GifFile->Error);
//exit(EXIT_FAILURE);
close();
return false;
}
}
}
else
{
for (i = 0; i < Height; i++) 
{
//GifQprintf("\b\b\b\b%-4d", i);
if (DGifGetLine(GifFile, &ScreenBuffer[Row++][Col],Width) == GIF_ERROR) 
{
//PrintGifError(GifFile->Error);
//exit(EXIT_FAILURE);
close();
return false;
}
}
}
dumpCurrentFrame();
//count++ ;
break;
case EXTENSION_RECORD_TYPE:
/* Skip any extension blocks in file: */
if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR)
{
//PrintGifError(GifFile->Error);
//exit(EXIT_FAILURE);
close();
return false;
}
while (Extension != NULL) 
{
if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR)
{
//PrintGifError(GifFile->Error);
//exit(EXIT_FAILURE);
close();
return false;
}
}
break;
case TERMINATE_RECORD_TYPE:
break;
default:    /* Should be trapped by DGifGetRecordType. */
break;
}
} while (RecordType != TERMINATE_RECORD_TYPE);
//printf("open finish:GifFile=%x width=%d,height=%d ScreenBuffer=%x\n",GifFile,GifFile->SWidth,GifFile->SHeight,ScreenBuffer);
//printf("Extension:%p \n",Extension);
//printf("count:%d\n",count);
//printf("SColorResolution=%d,SBackGroundColor=%d SavedImages=%p\n",GifFile->SColorResolution,GifFile->SBackGroundColor,GifFile->SavedImages);
//printf("Left=%d Top=%d Width=%d Height=%d Interlace=%d \n",GifFile->Image.Left,GifFile->Image.Top,GifFile->Image.Width,GifFile->Image.Height,GifFile->Image.Interlace);
return true;
}