egif_lib.c

Go to the documentation of this file.
00001 /******************************************************************************
00002 *   "Gif-Lib" - Yet another gif library.                                      *
00003 *                                                                             *
00004 * Written by:  Gershon Elber                            Ver 1.1, Aug. 1990    *
00005 *******************************************************************************
00006 * The kernel of the GIF Encoding process can be found here.                   *
00007 *******************************************************************************
00008 * History:                                                                    *
00009 * 14 Jun 89 - Version 1.0 by Gershon Elber.                                   *
00010 *  3 Sep 90 - Version 1.1 by Gershon Elber (Support for Gif89, Unique names). *
00011 * 26 Jun 96 - Version 3.0 by Eric S. Raymond (Full GIF89 support)
00012 ******************************************************************************/
00013 
00014 #ifdef _WIN32
00015 #include "../win32/config.h"
00016 #else
00017 #include "../config.h"
00018 #endif
00019 
00020 #ifdef __MSDOS__
00021 #include <alloc.h>
00022 #include <sys\stat.h>
00023 #else
00024 #include <sys/types.h>
00025 #include <sys/stat.h>
00026 #ifdef R6000
00027 /* FIXME: What is sys/mode.h?  Can we substitute a check for this file rather
00028  * than a check based on machine type?
00029  */
00030 #include <sys/mode.h>
00031 #endif
00032 #endif /* __MSDOS__ */
00033 
00034 #include <fcntl.h>
00035 #ifdef HAVE_UNISTD_H
00036 #include <unistd.h>
00037 #endif
00038 #ifdef HAVE_STDLIB_H
00039 #include <stdlib.h>
00040 #endif
00041 #include <stdio.h>
00042 #include <string.h>
00043 #include "gif_lib.h"
00044 #include "gif_lib_private.h"
00045 
00046 /* #define DEBUG_NO_PREFIX                        Dump only compressed data. */
00047 
00048 /* Masks given codes to BitsPerPixel, to make sure all codes are in range: */
00049 static GifPixelType CodeMask[] = {
00050     0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
00051 };
00052 
00053 static unsigned char GifVersionPrefix[GIF_STAMP_LEN + 1] = GIF87_STAMP;
00054 static int GifVersionPrefixLen = GIF_STAMP_LEN ;
00055 
00056 #define WRITE(_gif,_buf,_len)   \
00057   (((GifFilePrivateType*)_gif->Private)->Write ?    \
00058    ((GifFilePrivateType*)_gif->Private)->Write(_gif,(unsigned char *)_buf,(int)_len) :    \
00059    fwrite(_buf, 1, _len, ((GifFilePrivateType*)_gif->Private)->File))
00060 
00061 static int EGifPutWord(int Word, GifFileType *GifFile);
00062 static int EGifSetupCompress(GifFileType *GifFile);
00063 static int EGifCompressLine(GifFileType *GifFile, GifPixelType *Line,
00064                                                                 int LineLen);
00065 static int EGifCompressOutput(GifFileType *GifFile, int Code);
00066 static int EGifBufferedOutput(GifFileType *GifFile, GifByteType *Buf, int c);
00067 
00068 /******************************************************************************
00069 *   Update a new gif file, given its file handle, which must be opened for    *
00070 * write in binary mode.                                                       *
00071 *   Returns GifFileType pointer dynamically allocated which serves as the gif *
00072 * info record. _GifError is cleared if succesfull.                            *
00073 ******************************************************************************/
00074 GifFileType *EGifOpenFileHandle(int FileHandle)
00075 {
00076     GifFileType *GifFile;
00077     GifFilePrivateType *Private;
00078     FILE *f;
00079 
00080     if ((GifFile = (GifFileType *) malloc(sizeof(GifFileType))) == NULL) {
00081         _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
00082         return NULL;
00083     }
00084 
00085     memset(GifFile, '\0', sizeof(GifFileType));
00086 
00087     if ((Private = (GifFilePrivateType *)
00088                    malloc(sizeof(GifFilePrivateType))) == NULL) {
00089         free(GifFile);
00090         _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
00091         return NULL;
00092     }
00093     if ((Private->HashTable = _InitHashTable()) == NULL) {
00094         free(GifFile);
00095         free(Private);
00096         _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
00097         return NULL;
00098     }
00099 
00100 #ifdef __MSDOS__
00101     setmode(FileHandle, O_BINARY);      /* Make sure it is in binary mode. */
00102 #endif /* __MSDOS__ */
00103 
00104     f = fdopen(FileHandle, "wb");           /* Make it into a stream: */
00105 
00106 #ifdef __MSDOS__
00107     setvbuf(f, NULL, _IOFBF, GIF_FILE_BUFFER_SIZE);   /* And inc. stream buffer. */
00108 #endif /* __MSDOS__ */
00109 
00110     GifFile->Private = (VoidPtr) Private;
00111     Private->FileHandle = FileHandle;
00112     Private->File = f;
00113     Private->FileState = FILE_STATE_WRITE;
00114     
00115     Private->Write = (OutputFunc)0; /* No user write routine (MRB) */
00116     GifFile->UserData = (VoidPtr)0; /* No user write handle (MRB) */
00117     
00118     _GifError = 0;
00119 
00120     return GifFile;
00121 }
00122 
00123 /******************************************************************************
00124 * Output constructor that takes user supplied output function.                *
00125 * Basically just a copy of EGifOpenFileHandle. (MRB)                          *
00126 ******************************************************************************/
00127 GifFileType* EGifOpen(void* userData, OutputFunc writeFunc)
00128 {
00129     GifFileType* GifFile;
00130     GifFilePrivateType* Private;
00131 
00132      if ((GifFile = (GifFileType *) malloc(sizeof(GifFileType))) == NULL) {
00133         _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
00134         return NULL;
00135     }
00136 
00137     memset(GifFile, '\0', sizeof(GifFileType));
00138 
00139     if ((Private = (GifFilePrivateType *)
00140                    malloc(sizeof(GifFilePrivateType))) == NULL) {
00141         free(GifFile);
00142         _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
00143         return NULL;
00144     }
00145 
00146     Private->HashTable = _InitHashTable();
00147     if (Private->HashTable == NULL) {
00148         free (GifFile);
00149         free (Private);
00150         _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
00151         return NULL;
00152     }
00153 
00154     GifFile->Private = (VoidPtr) Private;
00155     Private->FileHandle = 0;
00156     Private->File = (FILE *)0;
00157     Private->FileState = FILE_STATE_WRITE;
00158     
00159     Private->Write = writeFunc; /* User write routine (MRB) */
00160     GifFile->UserData = userData; /* User write handle (MRB) */
00161     
00162     _GifError = 0;
00163 
00164     return GifFile;
00165 }
00166 
00167 /******************************************************************************
00168 *   Routine to set current GIF version. All files open for write will be      *
00169 * using this version until next call to this routine. Version consists of     *
00170 * 3 characters as "87a" or "89a". No test is made to validate the version.    *
00171 ******************************************************************************/
00172 void EGifSetGifVersion(const char *Version)
00173 {
00174     memcpy(GifVersionPrefix + GIF_VERSION_POS, Version, 3);
00175 }
00176 
00177 /******************************************************************************
00178 *   This routine should be called before any other EGif calls, immediately    *
00179 * follows the GIF file openning.                                              *
00180 ******************************************************************************/
00181 int EGifPutScreenDesc(GifFileType *GifFile,
00182         int Width, int Height, int ColorRes, int BackGround,
00183         const ColorMapObject *ColorMap)
00184 {
00185     int i;
00186     GifByteType Buf[3];
00187     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
00188 
00189     if (Private->FileState & FILE_STATE_SCREEN) {
00190         /* If already has screen descriptor - something is wrong! */
00191         _GifError = E_GIF_ERR_HAS_SCRN_DSCR;
00192         return GIF_ERROR;
00193     }
00194     if (!IS_WRITEABLE(Private)) {
00195         /* This file was NOT open for writing: */
00196         _GifError = E_GIF_ERR_NOT_WRITEABLE;
00197         return GIF_ERROR;
00198     }
00199 
00200 /* First write the version prefix into the file. */
00201 #ifndef DEBUG_NO_PREFIX
00202     if (WRITE(GifFile, GifVersionPrefix, GifVersionPrefixLen) !=
00203                                                 GifVersionPrefixLen) {
00204         _GifError = E_GIF_ERR_WRITE_FAILED;
00205         return GIF_ERROR;
00206     }
00207 #endif /* DEBUG_NO_PREFIX */
00208 
00209     GifFile->SWidth = Width;
00210     GifFile->SHeight = Height;
00211     GifFile->SColorResolution = ColorRes;
00212     GifFile->SBackGroundColor = BackGround;
00213     if(ColorMap)
00214         {
00215                 GifFile->SColorMap=MakeMapObject(ColorMap->ColorCount,ColorMap->Colors);
00216 
00217         if (GifFile->SColorMap == NULL) 
00218                 {
00219             _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
00220             return GIF_ERROR;
00221         }
00222     }else
00223       GifFile->SColorMap=NULL;
00224 
00225     /* Put the screen descriptor into the file: */
00226     EGifPutWord(Width, GifFile);
00227     EGifPutWord(Height, GifFile);
00228         if( ColorMap ) 
00229         Buf[0] = 0x80 | ((ColorRes - 1) << 4) | (ColorMap->BitsPerPixel - 1);
00230         else
00231         Buf[0] = 0x00 | ((ColorRes - 1) << 4) ;
00232     Buf[1] = BackGround;
00233     Buf[2] = 0;
00234 #ifndef DEBUG_NO_PREFIX
00235     WRITE(GifFile, Buf, 3);
00236 #endif /* DEBUG_NO_PREFIX */
00237 
00238     /* If we have Global color map - dump it also: */
00239 #ifndef DEBUG_NO_PREFIX
00240     if (ColorMap != NULL)
00241         for (i = 0; i < ColorMap->ColorCount; i++) {
00242             /* Put the ColorMap out also: */
00243             Buf[0] = ColorMap->Colors[i].Red;
00244             Buf[1] = ColorMap->Colors[i].Green;
00245             Buf[2] = ColorMap->Colors[i].Blue;
00246             if (WRITE(GifFile, Buf, 3) != 3) {
00247                 _GifError = E_GIF_ERR_WRITE_FAILED;
00248                 return GIF_ERROR;
00249             }
00250         }
00251 #endif /* DEBUG_NO_PREFIX */
00252 
00253     /* Mark this file as has screen descriptor, and no pixel written yet: */
00254     Private->FileState |= FILE_STATE_SCREEN;
00255 
00256     return GIF_OK;
00257 }
00258 
00259 /******************************************************************************
00260 *   This routine should be called before any attemp to dump an image - any    *
00261 * call to any of the pixel dump routines.                                     *
00262 ******************************************************************************/
00263 int EGifPutImageDesc(GifFileType *GifFile,
00264         int Left, int Top, int Width, int Height, int Interlace,
00265         const ColorMapObject *ColorMap)
00266 {
00267     int i;
00268     GifByteType Buf[3];
00269     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
00270 
00271     if (Private->FileState & FILE_STATE_IMAGE &&
00272 #if defined(__MSDOS__) || defined(__GNUC__)
00273         Private->PixelCount > 0xffff0000UL) {
00274 #else
00275         Private->PixelCount > 0xffff0000) {
00276 #endif /* __MSDOS__ */
00277         /* If already has active image descriptor - something is wrong! */
00278         _GifError = E_GIF_ERR_HAS_IMAG_DSCR;
00279         return GIF_ERROR;
00280     }
00281     if (!IS_WRITEABLE(Private)) {
00282         /* This file was NOT open for writing: */
00283         _GifError = E_GIF_ERR_NOT_WRITEABLE;
00284         return GIF_ERROR;
00285     }
00286     GifFile->Image.Left = Left;
00287     GifFile->Image.Top = Top;
00288     GifFile->Image.Width = Width;
00289     GifFile->Image.Height = Height;
00290     GifFile->Image.Interlace = Interlace;
00291     if(ColorMap)
00292         {
00293       GifFile->Image.ColorMap =MakeMapObject(ColorMap->ColorCount,ColorMap->Colors);
00294         if (GifFile->Image.ColorMap == NULL) 
00295                 {
00296             _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
00297             return GIF_ERROR;
00298         }
00299     }else
00300       GifFile->Image.ColorMap = NULL;
00301 
00302     /* Put the image descriptor into the file: */
00303     Buf[0] = ',';                              /* Image seperator character. */
00304 #ifndef DEBUG_NO_PREFIX
00305     WRITE(GifFile, Buf, 1);
00306 #endif /* DEBUG_NO_PREFIX */
00307     EGifPutWord(Left, GifFile);
00308     EGifPutWord(Top, GifFile);
00309     EGifPutWord(Width, GifFile);
00310     EGifPutWord(Height, GifFile);
00311     Buf[0] = (ColorMap ? 0x80 : 0x00) |
00312           (Interlace ? 0x40 : 0x00) |
00313           (ColorMap ? ColorMap->BitsPerPixel - 1 : 0);
00314 #ifndef DEBUG_NO_PREFIX
00315     WRITE(GifFile, Buf, 1);
00316 #endif /* DEBUG_NO_PREFIX */
00317 
00318     /* If we have Global color map - dump it also: */
00319 #ifndef DEBUG_NO_PREFIX
00320     if (ColorMap != NULL)
00321         for (i = 0; i < ColorMap->ColorCount; i++) {
00322             /* Put the ColorMap out also: */
00323             Buf[0] = ColorMap->Colors[i].Red;
00324             Buf[1] = ColorMap->Colors[i].Green;
00325             Buf[2] = ColorMap->Colors[i].Blue;
00326             if (WRITE(GifFile, Buf, 3) != 3) {
00327                 _GifError = E_GIF_ERR_WRITE_FAILED;
00328                 return GIF_ERROR;
00329             }
00330         }
00331 #endif /* DEBUG_NO_PREFIX */
00332     if (GifFile->SColorMap == NULL && GifFile->Image.ColorMap == NULL)
00333     {
00334         _GifError = E_GIF_ERR_NO_COLOR_MAP;
00335         return GIF_ERROR;
00336     }
00337 
00338     /* Mark this file as has screen descriptor: */
00339     Private->FileState |= FILE_STATE_IMAGE;
00340     Private->PixelCount = (long) Width * (long) Height;
00341 
00342     EGifSetupCompress(GifFile);      /* Reset compress algorithm parameters. */
00343 
00344     return GIF_OK;
00345 }
00346 
00347 /******************************************************************************
00348 *  Put one full scanned line (Line) of length LineLen into GIF file.          *
00349 ******************************************************************************/
00350 int EGifPutLine(GifFileType *GifFile, GifPixelType *Line, int LineLen)
00351 {
00352     int i;
00353     GifPixelType Mask;
00354     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
00355 
00356     if (!IS_WRITEABLE(Private)) {
00357         /* This file was NOT open for writing: */
00358         _GifError = E_GIF_ERR_NOT_WRITEABLE;
00359         return GIF_ERROR;
00360     }
00361 
00362     if (!LineLen)
00363       LineLen = GifFile->Image.Width;
00364     if (Private->PixelCount < (unsigned)LineLen) {
00365         _GifError = E_GIF_ERR_DATA_TOO_BIG;
00366         return GIF_ERROR;
00367     }
00368     Private->PixelCount -= LineLen;
00369 
00370     /* Make sure the codes are not out of bit range, as we might generate    */
00371     /* wrong code (because of overflow when we combine them) in this case:   */
00372     Mask = CodeMask[Private->BitsPerPixel];
00373     for (i = 0; i < LineLen; i++) Line[i] &= Mask;
00374 
00375     return EGifCompressLine(GifFile, Line, LineLen);
00376 }
00377 
00378 /******************************************************************************
00379 * Put a comment into GIF file using the GIF89 comment extension block.        *
00380 ******************************************************************************/
00381 int EGifPutComment(GifFileType *GifFile, const char *Comment)
00382 {
00383     unsigned int length = strlen(Comment);
00384     char *buf;
00385 
00386     length = strlen(Comment);
00387     if (length <= 255) {
00388         return EGifPutExtension(GifFile, COMMENT_EXT_FUNC_CODE,
00389                                 length, Comment);
00390     } else {
00391         buf = (char *)Comment;
00392         if (EGifPutExtensionFirst(GifFile, COMMENT_EXT_FUNC_CODE, 255, buf)
00393                 == GIF_ERROR) {
00394             return GIF_ERROR;
00395         }
00396         length -= 255;
00397         buf = buf + 255;
00398 
00399         /* Break the comment into 255 byte sub blocks */
00400         while (length > 255) {
00401             if (EGifPutExtensionNext(GifFile, 0, 255, buf) == GIF_ERROR) {
00402                 return GIF_ERROR;
00403             }
00404             buf = buf + 255;
00405             length -= 255;
00406         }
00407         /* Output any partial block and the clear code. */
00408         if (length > 0) {
00409             if (EGifPutExtensionLast(GifFile, 0, length, buf) == GIF_ERROR) {
00410                 return GIF_ERROR;
00411             }
00412         } else {
00413             if (EGifPutExtensionLast(GifFile, 0, 0, NULL) == GIF_ERROR) {
00414                 return GIF_ERROR;
00415             }
00416         }
00417     }
00418     return GIF_OK;
00419 }
00420 
00421 /******************************************************************************
00422 *   Put a first extension block (see GIF manual) into gif file.  Here more    *
00423 * extensions can be dumped using EGifPutExtensionMid until                    *
00424 * EGifPutExtensionLast is invoked.                                            *
00425 ******************************************************************************/
00426 int EGifPutExtensionFirst(GifFileType *GifFile, int ExtCode, int ExtLen,
00427                                                         const VoidPtr Extension)
00428 {
00429     GifByteType Buf[3];
00430     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
00431 
00432     if (!IS_WRITEABLE(Private)) {
00433         /* This file was NOT open for writing: */
00434         _GifError = E_GIF_ERR_NOT_WRITEABLE;
00435         return GIF_ERROR;
00436     }
00437 
00438     if (ExtCode == 0)
00439         fwrite(&ExtLen, 1, 1, Private->File);
00440     else
00441     {
00442         Buf[0] = '!';
00443         Buf[1] = ExtCode;
00444         Buf[2] = ExtLen;
00445         fwrite(Buf, 1, 3, Private->File);
00446     }
00447     fwrite(Extension, 1, ExtLen, Private->File);
00448 
00449     return GIF_OK;
00450 }
00451 
00452 /******************************************************************************
00453 *   Put a middle extension block (see GIF manual) into gif file.              *
00454 ******************************************************************************/
00455 int EGifPutExtensionNext(GifFileType *GifFile, int ExtCode, int ExtLen,
00456                                                         const VoidPtr Extension)
00457 {
00458     GifByteType Buf;
00459     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
00460 
00461     if (!IS_WRITEABLE(Private)) {
00462         /* This file was NOT open for writing: */
00463         _GifError = E_GIF_ERR_NOT_WRITEABLE;
00464         return GIF_ERROR;
00465     }
00466 
00467     Buf = ExtLen;
00468     fwrite(&Buf, 1, 1, Private->File);
00469     fwrite(Extension, 1, ExtLen, Private->File);
00470 
00471     return GIF_OK;
00472 }
00473 
00474 /******************************************************************************
00475 *   Put a last extension block (see GIF manual) into gif file.                *
00476 ******************************************************************************/
00477 int EGifPutExtensionLast(GifFileType *GifFile, int ExtCode, int ExtLen,
00478                                                         const VoidPtr Extension)
00479 {
00480     GifByteType Buf;
00481     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
00482 
00483     if (!IS_WRITEABLE(Private)) {
00484         /* This file was NOT open for writing: */
00485         _GifError = E_GIF_ERR_NOT_WRITEABLE;
00486         return GIF_ERROR;
00487     }
00488 
00489     /* If we are given an extension sub-block output it now. */
00490     if (ExtLen > 0) 
00491         {
00492         Buf = ExtLen;
00493             fwrite(&Buf, 1, 1, Private->File);
00494         fwrite(Extension, 1, ExtLen, Private->File);
00495         }
00496 
00497     Buf = 0;
00498     fwrite(&Buf, 1, 1, Private->File);
00499 
00500     return GIF_OK;
00501 }
00502 
00503 /******************************************************************************
00504 *   Put an extension block (see GIF manual) into gif file.                    *
00505 ******************************************************************************/
00506 int EGifPutExtension(GifFileType *GifFile, int ExtCode, int ExtLen,
00507                                                   const VoidPtr Extension)
00508 {
00509     GifByteType Buf[3];
00510     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
00511 
00512     if (!IS_WRITEABLE(Private)) {
00513             /* This file was NOT open for writing: */
00514             _GifError = E_GIF_ERR_NOT_WRITEABLE;
00515             return GIF_ERROR;
00516     }
00517 
00518     if (ExtCode == 0)
00519         WRITE(GifFile, (GifByteType*)&ExtLen, 1);
00520     else {
00521             Buf[0] = '!';
00522             Buf[1] = ExtCode;
00523             Buf[2] = ExtLen;
00524         WRITE(GifFile, Buf, 3);
00525     }
00526     WRITE(GifFile, Extension, ExtLen);
00527     Buf[0] = 0;
00528     WRITE(GifFile, Buf, 1);
00529 
00530     return GIF_OK;
00531 }
00532 
00533 /******************************************************************************
00534 *   This routine should be called last, to close GIF file.                    *
00535 ******************************************************************************/
00536 int EGifCloseFile(GifFileType *GifFile)
00537 {
00538     GifByteType Buf;
00539     GifFilePrivateType *Private;
00540     FILE *File;
00541 
00542     if (GifFile == NULL) return GIF_ERROR;
00543 
00544     Private = (GifFilePrivateType *) GifFile->Private;
00545     if (!IS_WRITEABLE(Private)) {
00546         /* This file was NOT open for writing: */
00547         _GifError = E_GIF_ERR_NOT_WRITEABLE;
00548         return GIF_ERROR;
00549     }
00550 
00551     File = Private->File;
00552 
00553     Buf = ';';
00554     WRITE(GifFile, &Buf, 1);
00555 
00556     if (GifFile->Image.ColorMap) {
00557         FreeMapObject(GifFile->Image.ColorMap);
00558         GifFile->Image.ColorMap = NULL;
00559     }
00560     if (GifFile->SColorMap) {
00561         FreeMapObject(GifFile->SColorMap);
00562         GifFile->SColorMap = NULL;
00563     }
00564     if (Private) {
00565         if (Private->HashTable) {
00566             free((char *) Private->HashTable);
00567         }
00568             free((char *) Private);
00569     }
00570     free(GifFile);
00571 
00572     if (File && fclose(File) != 0) 
00573         {
00574                 _GifError = E_GIF_ERR_CLOSE_FAILED;
00575                 return GIF_ERROR;
00576     }
00577     return GIF_OK;
00578 }
00579 
00580 /******************************************************************************
00581 *   Put 2 bytes (word) into the given file:                                   *
00582 ******************************************************************************/
00583 static int EGifPutWord(int Word, GifFileType *GifFile)
00584 {
00585     unsigned char c[2];
00586 
00587     c[0] = Word & 0xff;
00588     c[1] = (Word >> 8) & 0xff;
00589 #ifndef DEBUG_NO_PREFIX
00590     if (WRITE(GifFile, c, 2) == 2)
00591         return GIF_OK;
00592     else
00593         return GIF_ERROR;
00594 #else
00595     return GIF_OK;
00596 #endif /* DEBUG_NO_PREFIX */
00597 }
00598 
00599 /******************************************************************************
00600 *   Setup the LZ compression for this image:                                  *
00601 ******************************************************************************/
00602 static int EGifSetupCompress(GifFileType *GifFile)
00603 {
00604     int BitsPerPixel;
00605     GifByteType Buf;
00606     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
00607 
00608     /* Test and see what color map to use, and from it # bits per pixel: */
00609     if (GifFile->Image.ColorMap)
00610         BitsPerPixel = GifFile->Image.ColorMap->BitsPerPixel;
00611     else if (GifFile->SColorMap)
00612         BitsPerPixel = GifFile->SColorMap->BitsPerPixel;
00613     else {
00614         _GifError = E_GIF_ERR_NO_COLOR_MAP;
00615         return GIF_ERROR;
00616     }
00617 
00618     Buf = BitsPerPixel = (BitsPerPixel < 2 ? 2 : BitsPerPixel);
00619     WRITE(GifFile, &Buf, 1);     /* Write the Code size to file. */
00620 
00621     Private->Buf[0] = 0;                          /* Nothing was output yet. */
00622     Private->BitsPerPixel = BitsPerPixel;
00623     Private->ClearCode = (1 << BitsPerPixel);
00624     Private->EOFCode = Private->ClearCode + 1;
00625     Private->RunningCode = Private->EOFCode + 1;
00626     Private->RunningBits = BitsPerPixel + 1;     /* Number of bits per code. */
00627     Private->MaxCode1 = 1 << Private->RunningBits;         /* Max. code + 1. */
00628     Private->CrntCode = FIRST_CODE;        /* Signal that this is first one! */
00629     Private->CrntShiftState = 0;      /* No information in CrntShiftDWord. */
00630     Private->CrntShiftDWord = 0;
00631 
00632        /* Clear hash table and send Clear to make sure the decoder do the same. */
00633     _ClearHashTable(Private->HashTable);
00634 
00635         /* Send Clear to make sure the encoder is initialized. */
00636     if (EGifCompressOutput(GifFile, Private->ClearCode) == GIF_ERROR) 
00637         {
00638                 _GifError = E_GIF_ERR_DISK_IS_FULL;
00639                 return GIF_ERROR;
00640     }
00641     return GIF_OK;
00642 }
00643 
00644 /******************************************************************************
00645 *   The LZ compression routine:                                               *
00646 *   This version compress the given buffer Line of length LineLen.            *
00647 *   This routine can be called few times (one per scan line, for example), in *
00648 * order the complete the whole image.                                         *
00649 ******************************************************************************/
00650 static int EGifCompressLine(GifFileType *GifFile, GifPixelType *Line,
00651                                                                 int LineLen)
00652 {
00653     int i = 0, CrntCode, NewCode;
00654         unsigned long NewKey;
00655         GifPixelType Pixel;
00656     GifHashTableType *HashTable;
00657         GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
00658 
00659         HashTable = Private->HashTable;
00660 
00661     if (Private->CrntCode == FIRST_CODE)    /* Its first time! */
00662         CrntCode = Line[i++];
00663     else
00664         CrntCode = Private->CrntCode;    /* Get last code in compression. */
00665 
00666     while (i < LineLen) {   /* Decode LineLen items. */
00667         Pixel = Line[i++];  /* Get next pixel from stream. */
00668         /* Form a new unique key to search hash table for the code combines 
00669          * CrntCode as Prefix string with Pixel as postfix char.
00670          */
00671         NewKey = (((UINT32) CrntCode) << 8) + Pixel;
00672         if ((NewCode = _ExistsHashTable(HashTable, NewKey)) >= 0) {
00673             /* This Key is already there, or the string is old one, so
00674              * simple take new code as our CrntCode:
00675              */
00676             CrntCode = NewCode;
00677         } else {
00678             /* Put it in hash table, output the prefix code, and make our
00679              * CrntCode equal to Pixel.
00680              */
00681             if (EGifCompressOutput(GifFile, CrntCode) == GIF_ERROR) {
00682                 _GifError = E_GIF_ERR_DISK_IS_FULL;
00683                 return GIF_ERROR;
00684             }
00685             CrntCode = Pixel;
00686 
00687             /* If however the HashTable if full, we send a clear first and
00688              * Clear the hash table.
00689              */
00690             if (Private->RunningCode >= LZ_MAX_CODE) {
00691                 /* Time to do some clearance: */
00692                 if (EGifCompressOutput(GifFile, Private->ClearCode)
00693                         == GIF_ERROR) {
00694                     _GifError = E_GIF_ERR_DISK_IS_FULL;
00695                     return GIF_ERROR;
00696                 }
00697                 Private->RunningCode = Private->EOFCode + 1;
00698                 Private->RunningBits = Private->BitsPerPixel + 1;
00699                 Private->MaxCode1 = 1 << Private->RunningBits;
00700                 _ClearHashTable(HashTable);
00701             } else {
00702                 /* Put this unique key with its relative Code in hash table: */
00703                 _InsertHashTable(HashTable, NewKey, Private->RunningCode++);
00704             }
00705         }
00706 
00707     }
00708 
00709     /* Preserve the current state of the compression algorithm: */
00710     Private->CrntCode = CrntCode;
00711 
00712     if (Private->PixelCount == 0) {
00713         /* We are done - output last Code and flush output buffers: */
00714         if (EGifCompressOutput(GifFile, CrntCode) == GIF_ERROR) {
00715             _GifError = E_GIF_ERR_DISK_IS_FULL;
00716             return GIF_ERROR;
00717         }
00718         if (EGifCompressOutput(GifFile, Private->EOFCode) == GIF_ERROR) {
00719             _GifError = E_GIF_ERR_DISK_IS_FULL;
00720             return GIF_ERROR;
00721         }
00722         if (EGifCompressOutput(GifFile, FLUSH_OUTPUT) == GIF_ERROR) {
00723             _GifError = E_GIF_ERR_DISK_IS_FULL;
00724             return GIF_ERROR;
00725         }
00726     }
00727 
00728     return GIF_OK;
00729 }
00730 
00731 /******************************************************************************
00732 *   The LZ compression output routine:                                        *
00733 *   This routine is responsible for the compression of the bit stream into    *
00734 *   8 bits (bytes) packets.                                                   *
00735 *   Returns GIF_OK if written succesfully.                                    *
00736 ******************************************************************************/
00737 static int EGifCompressOutput(GifFileType *GifFile, int Code)
00738 {
00739     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
00740     int retval = GIF_OK;
00741 
00742     if (Code == FLUSH_OUTPUT) {
00743                 while (Private->CrntShiftState > 0) {
00744                 /* Get Rid of what is left in DWord, and flush it. */
00745                 if (EGifBufferedOutput(GifFile, Private->Buf,
00746                         Private->CrntShiftDWord & 0xff) == GIF_ERROR)
00747                         retval = GIF_ERROR;
00748                 Private->CrntShiftDWord >>= 8;
00749                 Private->CrntShiftState -= 8;
00750                 }
00751                 Private->CrntShiftState = 0;                       /* For next time. */
00752                 if (EGifBufferedOutput(GifFile, Private->Buf,
00753                 FLUSH_OUTPUT) == GIF_ERROR)
00754                         retval = GIF_ERROR;
00755     } else {
00756                 Private->CrntShiftDWord |= ((long) Code) << Private->CrntShiftState;
00757                 Private->CrntShiftState += Private->RunningBits;
00758                 while (Private->CrntShiftState >= 8) {
00759                 /* Dump out full bytes: */
00760                 if (EGifBufferedOutput(GifFile, Private->Buf,
00761                         Private->CrntShiftDWord & 0xff) == GIF_ERROR)
00762                         retval = GIF_ERROR;
00763                 Private->CrntShiftDWord >>= 8;
00764                 Private->CrntShiftState -= 8;
00765                 }
00766     }
00767 
00768     /* If code cannt fit into RunningBits bits, must raise its size. Note */
00769     /* however that codes above 4095 are used for special signaling.      */
00770     if (Private->RunningCode >= Private->MaxCode1 && Code <= 4095) {
00771        Private->MaxCode1 = 1 << ++Private->RunningBits;
00772     }
00773 
00774     return retval;
00775 }
00776 
00777 /******************************************************************************
00778 *   This routines buffers the given characters until 255 characters are ready *
00779 * to be output. If Code is equal to -1 the buffer is flushed (EOF).           *
00780 *   The buffer is Dumped with first byte as its size, as GIF format requires. *
00781 *   Returns GIF_OK if written succesfully.                                    *
00782 ******************************************************************************/
00783 static int EGifBufferedOutput(GifFileType *GifFile, GifByteType *Buf, int c)
00784 {
00785     if (c == FLUSH_OUTPUT) {
00786         /* Flush everything out. */
00787         if (Buf[0] != 0 && WRITE(GifFile, Buf, Buf[0]+1) != (unsigned)(Buf[0] + 1))
00788         {
00789             _GifError = E_GIF_ERR_WRITE_FAILED;
00790             return GIF_ERROR;
00791         }
00792         /* Mark end of compressed data, by an empty block (see GIF doc): */
00793         Buf[0] = 0;
00794         if (WRITE(GifFile, Buf, 1) != 1)
00795         {
00796             _GifError = E_GIF_ERR_WRITE_FAILED;
00797             return GIF_ERROR;
00798         }
00799     }
00800     else {
00801         if (Buf[0] == 255) {
00802             /* Dump out this buffer - it is full: */
00803             if (WRITE(GifFile, Buf, Buf[0] + 1) != (unsigned)(Buf[0] + 1))
00804             {
00805                 _GifError = E_GIF_ERR_WRITE_FAILED;
00806                 return GIF_ERROR;
00807             }
00808             Buf[0] = 0;
00809         }
00810         Buf[++Buf[0]] = c;
00811     }
00812 
00813     return GIF_OK;
00814 }
00815 

Generated on Tue Jul 5 14:13:32 2011 for ROOT_528-00b_version by  doxygen 1.5.1