home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / graphics / gif-util.zip / EGIF_LIB.C < prev    next >
C/C++ Source or Header  |  1989-08-01  |  26KB  |  723 lines

  1. /*****************************************************************************
  2. *   "Gif-Lib" - Yet another gif library.                     *
  3. *                                         *
  4. * Written by:  Gershon Elber            IBM PC Ver 0.1,    Jun. 1989    *
  5. ******************************************************************************
  6. * The kernel of the GIF Encoding process can be found here.             *
  7. ******************************************************************************
  8. * History:                                     *
  9. * 14 Jun 89 - Version 1.0 by Gershon Elber.                     *
  10. *****************************************************************************/
  11.  
  12. #include <io.h>
  13. #include <fcntl.h>
  14. #include <stdio.h>
  15. #include <alloc.h>
  16. #include <string.h>
  17. #include <sys\stat.h>
  18. #include "gif_lib.h"
  19. #include "gif_hash.h"
  20.  
  21. #define PROGRAM_NAME    "GIF_LIBRARY"
  22. #define VERSION        "ß Version 1.0, "
  23.  
  24. #define COMMENT_EXT_FUNC_CODE    'C'   /* Extension function code for comment */
  25. #define GIF_STAMP    "GIF87a"      /* First chars in file - GIF stamp */
  26. #define ZL_MAX_CODE    4095        /* Biggest code possible in 12 bits. */
  27.  
  28. #define FILE_STATE_WRITE    0x01/* 1 write, 0 read - DGIF_LIB compatible */
  29. #define FILE_STATE_SCREEN    0x02
  30. #define FILE_STATE_IMAGE    0x04
  31.  
  32. #define FLUSH_OUTPUT        4096     /* Impossible code, to signal flush */
  33. #define FIRST_CODE        4097     /* Impossible code, to signal first */
  34.  
  35. #define IS_WRITEABLE(Private)    (Private -> FileState & FILE_STATE_WRITE)
  36.  
  37. /* #define DEBUG_NO_PREFIX            /* Dump only compressed data */
  38.  
  39. typedef struct GifFilePrivateType {
  40.     int FileState,
  41.     FileHandle,                 /* Where old this data goes to! */
  42.     BitsPerPixel,         /* Bits per pixel (Codes uses at list this + 1) */
  43.     ClearCode,                    /* The CLEAR LZ code */
  44.     EOFCode,                      /* The EOF LZ code */
  45.     RunningCode,             /* The next code algorithm can generate */
  46.     RunningBits, /* The number of bits required to represent RunningCode */
  47.     MaxCode1,/* 1 bigger than maximum possible code, in RunningBits bits */
  48.     CrntCode,                   /* Current algorithm code */
  49.     CrntShiftState;             /* Number of bits in CrntShiftDWord */
  50.     unsigned long CrntShiftDWord,      /* For bytes decomposition into codes */
  51.           PixelCount;
  52.     FILE *File;                           /* File as stream */
  53.     ByteType Buf[256];               /* Compressed output is buffered here */
  54.     GifHashTableType *HashTable;
  55. } GifFilePrivateType;
  56.  
  57. extern int _GifError;
  58.  
  59. /* Masks given codes to BitsPerPixel, to make sure all codes are in range: */
  60. static PixelType CodeMask[] = {
  61.     0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
  62. };
  63.  
  64. static char *VersionStr =
  65.     PROGRAM_NAME
  66.     "    IBMPC "
  67.     VERSION
  68.     "    Gershon Elber,    "
  69.     __DATE__ ",   " __TIME__ "\n"
  70.     "(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
  71.  
  72. static int EGifPutWord(int Word, FILE *File);
  73. static int EGifSetupCompress(GifFileType *GifFile);
  74. static int EGifCompressLine(GifFileType *GifFile, PixelType *Line, int LineLen);
  75. static int EGifCompressOutput(GifFilePrivateType *Private, int Code);
  76. static int EGifBufferedOutput(FILE *File, ByteType *Buf, int c);
  77.  
  78. /******************************************************************************
  79. *   Open a new gif file for write, given by its name. If TestExistance then   *
  80. * if the file exists this routines fails (returns NULL).              *
  81. *   Returns GifFileType pointer dynamically allocated which serves as the gif *
  82. * info record. _GifError is cleared if succesfull.                  *
  83. ******************************************************************************/
  84. GifFileType *EGifOpenFileName(char *FileName, int TestExistance)
  85. {
  86.     int FileHandle;
  87.  
  88.     if (TestExistance)
  89.     FileHandle = open(FileName,
  90.               O_WRONLY | O_CREAT | O_EXCL | O_BINARY,
  91.               S_IREAD | S_IWRITE);
  92.     else
  93.     FileHandle = open(FileName,
  94.               O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
  95.               S_IREAD | S_IWRITE);
  96.  
  97.     if (FileHandle == -1) {
  98.     _GifError = E_GIF_ERR_OpenFailed;
  99.     return NULL;
  100.     }
  101.  
  102.     return EGifOpenFileHandle(FileHandle);
  103. }
  104.  
  105. /******************************************************************************
  106. *   Update a new gif file, given its file handle, which must be opened for    *
  107. * write in binary mode.                                  *
  108. *   Returns GifFileType pointer dynamically allocated which serves as the gif *
  109. * info record. _GifError is cleared if succesfull.                  *
  110. ******************************************************************************/
  111. GifFileType *EGifOpenFileHandle(int FileHandle)
  112. {
  113.     GifFileType *GifFile;
  114.     GifFilePrivateType *Private;
  115.     FILE *f;
  116.  
  117.     setmode(FileHandle, O_BINARY);       /* Make sure it is in binary mode */
  118.     f = fdopen(FileHandle, "wb");           /* Make it into a stream: */
  119.     setvbuf(f, NULL, _IOFBF, FILE_BUFFER_SIZE);/* And increase stream buffer */
  120.  
  121.     if ((GifFile = (GifFileType *) malloc(sizeof(GifFileType))) == NULL) {
  122.     _GifError = E_GIF_ERR_NotEnoughMem;
  123.     return NULL;
  124.     }
  125.  
  126.     GifFile -> SWidth = GifFile -> SHeight =
  127.     GifFile -> SColorResolution = GifFile -> SBitsPerPixel =
  128.     GifFile -> SBackGroundColor =
  129.     GifFile -> ILeft = GifFile -> ITop = GifFile -> IWidth = GifFile -> IHeight =
  130.     GifFile -> IInterlace =
  131.     GifFile -> IBitsPerPixel = 0;
  132.  
  133.     GifFile -> SColorMap = GifFile -> IColorMap = NULL;
  134.  
  135. #   ifndef DEBUG_NO_PREFIX
  136.     if (fwrite(GIF_STAMP, 1, strlen(GIF_STAMP), f) != strlen(GIF_STAMP)) {
  137.     _GifError = E_GIF_ERR_WriteFailed;
  138.     free((char *) GifFile);
  139.     return NULL;
  140.     }
  141. #   endif DEBUG_NO_PREFIX
  142.  
  143.     if ((Private = (GifFilePrivateType *) malloc(sizeof(GifFilePrivateType)))
  144.     == NULL) {
  145.     _GifError = E_GIF_ERR_NotEnoughMem;
  146.     return NULL;
  147.     }
  148.  
  149.     GifFile -> Private = (void *) Private;
  150.     Private -> FileHandle = FileHandle;
  151.     Private -> File = f;
  152.     Private -> FileState = FILE_STATE_WRITE;
  153.     if ((Private -> HashTable = _InitHashTable()) == NULL) {
  154.     _GifError = E_GIF_ERR_NotEnoughMem;
  155.     return NULL;
  156.     }
  157.  
  158.     _GifError = 0;
  159.  
  160.     return GifFile;
  161. }
  162.  
  163. /******************************************************************************
  164. *   This routine should be called before any other EGif calls, immediately    *
  165. * follows the GIF file openning.                          *
  166. ******************************************************************************/
  167. int EGifPutScreenDesc(GifFileType *GifFile,
  168.     int Width, int Height, int ColorRes, int BackGround,
  169.     int BitsPerPixel, GifColorType *ColorMap)
  170. {
  171.     int i, Size;
  172.     ByteType Buf[3];
  173.     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
  174.  
  175.     if (Private -> FileState & FILE_STATE_SCREEN) {
  176.     /* If already has screen descriptor - something is wrong! */
  177.     _GifError = E_GIF_ERR_HasScrnDscr;
  178.     return ERROR;
  179.     }
  180.     if (!IS_WRITEABLE(Private)) {
  181.     /* This file was NOT open for writing: */
  182.     _GifError = E_GIF_ERR_NotWriteable;
  183.     return ERROR;
  184.     }
  185.  
  186.     GifFile -> SWidth = Width;
  187.     GifFile -> SHeight = Height;
  188.     GifFile -> SColorResolution = ColorRes;
  189.     GifFile -> SBitsPerPixel = BitsPerPixel;
  190.     GifFile -> SBackGroundColor = BackGround;
  191.     if (ColorMap) {
  192.     Size = sizeof(GifColorType) * (1 << BitsPerPixel);
  193.     GifFile -> SColorMap = (GifColorType *) malloc(Size);
  194.     memcpy(GifFile -> SColorMap, ColorMap, Size);
  195.     }
  196.  
  197.     /* Put the screen descriptor into the file: */
  198.     EGifPutWord(Width, Private -> File);
  199.     EGifPutWord(Height, Private -> File);
  200.     Buf[0] = (ColorMap ? 0x80 : 0x00) |
  201.          ((ColorRes - 1) << 4) |
  202.          (BitsPerPixel - 1);
  203.     Buf[1] = BackGround;
  204.     Buf[2] = 0;
  205. #   ifndef DEBUG_NO_PREFIX
  206.     fwrite(Buf, 1, 3, Private -> File);
  207. #   endif DEBUG_NO_PREFIX
  208.  
  209.     /* If we have Global color map - dump it also: */
  210. #   ifndef DEBUG_NO_PREFIX
  211.     if (ColorMap != NULL)
  212.     for (i=0; i<(1 << BitsPerPixel); i++) {/* Put the ColorMap out also: */
  213.         Buf[0] = ColorMap[i].Red;
  214.         Buf[1] = ColorMap[i].Green;
  215.         Buf[2] = ColorMap[i].Blue;
  216.         if (fwrite(Buf, 1, 3, Private -> File) != 3) {
  217.             _GifError = E_GIF_ERR_WriteFailed;
  218.         return ERROR;
  219.         }
  220.     }
  221. #   endif DEBUG_NO_PREFIX
  222.  
  223.     /* Mark this file as has screen descriptor, and no pixel written yet: */
  224.     Private -> FileState |= FILE_STATE_SCREEN;
  225.  
  226.     return OK;
  227. }
  228.  
  229. /******************************************************************************
  230. *   This routine should be called before any attemp to dump an image - any    *
  231. * call to any of the pixel dump routines.                      *
  232. ******************************************************************************/
  233. int EGifPutImageDesc(GifFileType *GifFile,
  234.     int Left, int Top, int Width, int Height, int Interlace,
  235.     int BitsPerPixel, GifColorType *ColorMap)
  236. {
  237.     int i, Size;
  238.     ByteType Buf[3];
  239.     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
  240.  
  241.     if (Private -> FileState & FILE_STATE_IMAGE &&
  242.     Private -> PixelCount > 0) {
  243.     /* If already has active image descriptor - something is wrong! */
  244.     _GifError = E_GIF_ERR_HasImagDscr;
  245.     return ERROR;
  246.     }
  247.     if (!IS_WRITEABLE(Private)) {
  248.     /* This file was NOT open for writing: */
  249.     _GifError = E_GIF_ERR_NotWriteable;
  250.     return ERROR;
  251.     }
  252.     GifFile -> ILeft = Left;
  253.     GifFile -> ITop = Top;
  254.     GifFile -> IWidth = Width;
  255.     GifFile -> IHeight = Height;
  256.     GifFile -> IBitsPerPixel = BitsPerPixel;
  257.     GifFile -> IInterlace = Interlace;
  258.     if (ColorMap) {
  259.     Size = sizeof(GifColorType) * (1 << BitsPerPixel);
  260.     if (GifFile -> IColorMap) free((char *) GifFile -> IColorMap);
  261.     GifFile -> IColorMap = (GifColorType *) malloc(Size);
  262.     memcpy(GifFile -> IColorMap, ColorMap, Size);
  263.     }
  264.  
  265.     /* Put the image descriptor into the file: */
  266.     Buf[0] = ',';                /* Image seperator character */
  267. #   ifndef DEBUG_NO_PREFIX
  268.     fwrite(Buf, 1, 1, Private -> File);
  269. #   endif DEBUG_NO_PREFIX
  270.     EGifPutWord(Left, Private -> File);
  271.     EGifPutWord(Top, Private -> File);
  272.     EGifPutWord(Width, Private -> File);
  273.     EGifPutWord(Height, Private -> File);
  274.     Buf[0] = (ColorMap ? 0x80 : 0x00) |
  275.       (Interlace ? 0x40 : 0x00) |
  276.       (BitsPerPixel - 1);
  277. #   ifndef DEBUG_NO_PREFIX
  278.     fwrite(Buf, 1, 1, Private -> File);
  279. #   endif DEBUG_NO_PREFIX
  280.  
  281.     /* If we have Global color map - dump it also: */
  282. #   ifndef DEBUG_NO_PREFIX
  283.     if (ColorMap != NULL)
  284.     for (i=0; i<(1 << BitsPerPixel); i++) {/* Put the ColorMap out also: */
  285.         Buf[0] = ColorMap[i].Red;
  286.         Buf[1] = ColorMap[i].Green;
  287.         Buf[2] = ColorMap[i].Blue;
  288.         if (fwrite(Buf, 1, 3, Private -> File) != 3) {
  289.             _GifError = E_GIF_ERR_WriteFailed;
  290.         return ERROR;
  291.         }
  292.     }
  293. #   endif DEBUG_NO_PREFIX
  294.     if (GifFile -> SColorMap == NULL && GifFile -> IColorMap == NULL)
  295.     {
  296.     _GifError = E_GIF_ERR_NoColorMap;
  297.     return ERROR;
  298.     }
  299.  
  300.     /* Mark this file as has screen descriptor: */
  301.     Private -> FileState |= FILE_STATE_IMAGE;
  302.     Private -> PixelCount = (long) Width * (long) Height;
  303.  
  304.     EGifSetupCompress(GifFile);       /* Reset compress algorithm parameters */
  305.  
  306.     return OK;
  307. }
  308.  
  309. /******************************************************************************
  310. *  Put one full scanned line (Line) of length LineLen into GIF file.          *
  311. ******************************************************************************/
  312. int EGifPutLine(GifFileType *GifFile, PixelType *Line, int LineLen)
  313. {
  314.     int i;
  315.     PixelType Mask;
  316.     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
  317.  
  318.     if (!IS_WRITEABLE(Private)) {
  319.     /* This file was NOT open for writing: */
  320.     _GifError = E_GIF_ERR_NotWriteable;
  321.     return ERROR;
  322.     }
  323.  
  324.     if (!LineLen) LineLen = GifFile -> IWidth;
  325.     if ((Private -> PixelCount -= LineLen) < 0) {
  326.     _GifError = E_GIF_ERR_DataTooBig;
  327.     return ERROR;
  328.     }
  329.  
  330.     /* Make sure the codes are not out of bit range, as we might generate    */
  331.     /* wrong code (because of overflow when we combine them) in this case:   */
  332.     Mask = CodeMask[Private -> BitsPerPixel];
  333.     for (i=0; i<LineLen; i++) Line[i] &= Mask;
  334.  
  335.     return EGifCompressLine(GifFile, Line, LineLen);
  336. }
  337.  
  338. /******************************************************************************
  339. * Put one pixel (Pixel) into GIF file.                          *
  340. ******************************************************************************/
  341. int EGifPutPixel(GifFileType *GifFile, PixelType Pixel)
  342. {
  343.     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
  344.  
  345.     if (!IS_WRITEABLE(Private)) {
  346.     /* This file was NOT open for writing: */
  347.     _GifError = E_GIF_ERR_NotWriteable;
  348.     return ERROR;
  349.     }
  350.  
  351.     if (--Private -> PixelCount < 0)
  352.     {
  353.     _GifError = E_GIF_ERR_DataTooBig;
  354.     return ERROR;
  355.     }
  356.  
  357.     /* Make sure the code is not out of bit range, as we might generate         */
  358.     /* wrong code (because of overflow when we combine them) in this case:   */
  359.     Pixel &= CodeMask[Private -> BitsPerPixel];
  360.  
  361.     return EGifCompressLine(GifFile, &Pixel, 1);
  362. }
  363.  
  364. /******************************************************************************
  365. * Put a comment into GIF file using extension block.                  *
  366. ******************************************************************************/
  367. int EGifPutComment(GifFileType *GifFile, char *Comment)
  368. {
  369.     return EGifPutExtension(GifFile, COMMENT_EXT_FUNC_CODE, strlen(Comment),
  370.                                 Comment);
  371. }
  372.  
  373. /******************************************************************************
  374. *   Put an extension block (see GIF manual) into gif file.              *
  375. ******************************************************************************/
  376. int EGifPutExtension(GifFileType *GifFile, int ExtCode, int ExtLen,
  377.                             void *Extension)
  378. {
  379.     ByteType Buf[3];
  380.     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
  381.  
  382.     if (!IS_WRITEABLE(Private)) {
  383.     /* This file was NOT open for writing: */
  384.     _GifError = E_GIF_ERR_NotWriteable;
  385.     return ERROR;
  386.     }
  387.  
  388.     Buf[0] = '!';
  389.     Buf[1] = ExtCode;
  390.     Buf[2] = ExtLen;
  391.     fwrite(Buf, 1, 3, Private -> File);
  392.     fwrite(Extension, 1, ExtLen, Private -> File);
  393.     Buf[0] = 0;
  394.     fwrite(Buf, 1, 1, Private -> File);
  395.  
  396.     return OK;
  397. }
  398.  
  399. /******************************************************************************
  400. *   Put the image code in compressed form. This routine can be called if the  *
  401. * information needed to be piped out as is. Obviously this is much faster     *
  402. * than decoding and encoding again. This routine should be followed by calls  *
  403. * to EGifPutCodeNext, until NULL block is given.                  *
  404. *   The block should NOT be freed by the user (not dynamically allocated).    *
  405. ******************************************************************************/
  406. int EGifPutCode(GifFileType *GifFile, int CodeSize, ByteType *CodeBlock)
  407. {
  408.     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
  409.  
  410.     if (!IS_WRITEABLE(Private)) {
  411.     /* This file was NOT open for writing: */
  412.     _GifError = E_GIF_ERR_NotWriteable;
  413.     return ERROR;
  414.     }
  415.  
  416.     /* No need to dump code size as Compression set up does any for us: */
  417.     /*
  418.     Buf = CodeSize;
  419.     if (fwrite(&Buf, 1, 1, Private -> File) != 1) {
  420.     _GifError = E_GIF_ERR_WriteFailed;
  421.     return ERROR;
  422.     }
  423.     */
  424.  
  425.     return EGifPutCodeNext(GifFile, CodeBlock);
  426. }
  427.  
  428. /******************************************************************************
  429. *   Continue to put the image code in compressed form. This routine should be *
  430. * called with blocks of code as read via DGifGetCode/DGifGetCodeNext. If      *
  431. * given buffer pointer is NULL, empty block is written to mark end of code.   *
  432. ******************************************************************************/
  433. int EGifPutCodeNext(GifFileType *GifFile, ByteType *CodeBlock)
  434. {
  435.     ByteType Buf;
  436.     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
  437.  
  438.     if (CodeBlock != NULL) {
  439.     if (fwrite(CodeBlock, 1, CodeBlock[0] + 1, Private -> File)
  440.                             != CodeBlock[0] + 1) {
  441.         _GifError = E_GIF_ERR_WriteFailed;
  442.         return ERROR;
  443.     }
  444.     }
  445.     else {
  446.     Buf = 0;
  447.     if (fwrite(&Buf, 1, 1, Private -> File) != 1) {
  448.         _GifError = E_GIF_ERR_WriteFailed;
  449.         return ERROR;
  450.     }
  451.     Private -> PixelCount = 0;    /* And local info. indicate image read */
  452.     }
  453.  
  454.     return OK;
  455. }
  456.  
  457. /******************************************************************************
  458. *   This routine should be called last, to close GIF file.              *
  459. ******************************************************************************/
  460. int EGifCloseFile(GifFileType *GifFile)
  461. {
  462.     ByteType Buf;
  463.     GifFilePrivateType *Private;
  464.     FILE *File;
  465.  
  466.     if (GifFile == NULL) return ERROR;
  467.  
  468.     Private = (GifFilePrivateType *) GifFile -> Private;
  469.     if (!IS_WRITEABLE(Private)) {
  470.     /* This file was NOT open for writing: */
  471.     _GifError = E_GIF_ERR_NotWriteable;
  472.     return ERROR;
  473.     }
  474.  
  475.     File = Private -> File;
  476.  
  477.     Buf = ';';
  478.     fwrite(&Buf, 1, 1, Private -> File);
  479.  
  480.     if (GifFile -> IColorMap) free((char *) GifFile -> IColorMap);
  481.     if (GifFile -> SColorMap) free((char *) GifFile -> SColorMap);
  482.     if (Private) {
  483.     if (Private -> HashTable) free((char *) Private -> HashTable);
  484.     free((char *) Private);
  485.     }
  486.     free(GifFile);
  487.  
  488.     if (fclose(File) != 0) {
  489.     _GifError = E_GIF_ERR_CloseFailed;
  490.     return ERROR;
  491.     }
  492.     return OK;
  493. }
  494.  
  495. /******************************************************************************
  496. *   Put 2 bytes (word) into the given file:                      *
  497. ******************************************************************************/
  498. static int EGifPutWord(int Word, FILE *File)
  499. {
  500.     char c[2];
  501.  
  502.     c[0] = Word & 0xff;
  503.     c[1] = (Word >> 8) & 0xff;
  504. #   ifndef DEBUG_NO_PREFIX
  505.     if (fwrite(c, 1, 2, File) == 2)
  506.      return OK;
  507.     else return ERROR;
  508. #   else
  509.     return OK;
  510. #   endif DEBUG_NO_PREFIX
  511. }
  512.  
  513. /******************************************************************************
  514. *   Setup the LZ compression for this image:                      *
  515. ******************************************************************************/
  516. static int EGifSetupCompress(GifFileType *GifFile)
  517. {
  518.     int BitsPerPixel;
  519.     ByteType Buf;
  520.     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
  521.  
  522.     /* Test and see what color map to use, and from it # bits per pixel: */
  523.     if (GifFile -> IColorMap)
  524.      BitsPerPixel = GifFile -> IBitsPerPixel;
  525.     else
  526.     if (GifFile -> SColorMap)
  527.      BitsPerPixel = GifFile -> SBitsPerPixel;
  528.     else {
  529.     _GifError = E_GIF_ERR_NoColorMap;
  530.     return ERROR;
  531.     }
  532.  
  533.     Buf = BitsPerPixel = (BitsPerPixel < 2 ? 2 : BitsPerPixel);
  534.     fwrite(&Buf, 1, 1, Private -> File);      /* Write the Code size to file */
  535.  
  536.     Private -> Buf[0] = 0;               /* Nothing was output yet */
  537.     Private -> BitsPerPixel = BitsPerPixel;
  538.     Private -> ClearCode = (1 << BitsPerPixel);
  539.     Private -> EOFCode = Private -> ClearCode + 1;
  540.     Private -> RunningCode = Private -> EOFCode + 1;
  541.     Private -> RunningBits = BitsPerPixel + 1;      /* Number of bits per code */
  542.     Private -> MaxCode1 = 1 << Private -> RunningBits;        /* Max. code + 1 */
  543.     Private -> CrntCode = FIRST_CODE;       /* Signal that this is first one! */
  544.     Private -> CrntShiftState = 0;     /* No information in CrntShiftDWord */
  545.     Private -> CrntShiftDWord = 0;
  546.  
  547.     /* Clear hash table and send Clear to make sure the decoder do the same  */
  548.     _ClearHashTable(Private -> HashTable);
  549.     if (EGifCompressOutput(Private, Private -> ClearCode) == ERROR) {
  550.     _GifError = E_GIF_ERR_DiskIsFull;
  551.     return ERROR;
  552.     }
  553.     return OK;
  554. }
  555.  
  556. /******************************************************************************
  557. *   The LZ compression routine:                              *
  558. *   This version compress the given buffer Line of length LineLen.          *
  559. *   This routine can be called few times (one per scan line, for example), in *
  560. * order the complete the whole image.                          *
  561. ******************************************************************************/
  562. static int EGifCompressLine(GifFileType *GifFile, PixelType *Line, int LineLen)
  563. {
  564.     int i = 0, CrntCode, NewCode;
  565.     unsigned long NewKey;
  566.     PixelType Pixel;
  567.     GifHashTableType *HashTable;
  568.     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
  569.  
  570.     HashTable = Private -> HashTable;
  571.  
  572.     if (Private -> CrntCode == FIRST_CODE)          /* Its first time! */
  573.      CrntCode = Line[i++];
  574.     else CrntCode = Private -> CrntCode;     /* Get last code in compression */
  575.  
  576.     while (i < LineLen) {                /* Decode LineLen items. */
  577.     Pixel = Line[i++];               /* Get next pixel from stream */
  578.     /* Form a new unique key to search hash table for the code combines  */
  579.     /* CrntCode as Prefix string with Pixel as postfix char.         */
  580.     NewKey = (((unsigned long) CrntCode) << 8) + Pixel;
  581.     if ((NewCode = _ExistsHashTable(HashTable, NewKey)) >= 0) {
  582.         /* This Key is already there, or the string is old one, so         */
  583.         /* simple take new code as our CrntCode:                 */
  584.         CrntCode = NewCode;
  585.     }
  586.     else {
  587.         /* Put it in hash table, output the prefix code, and make our    */
  588.         /* CrntCode equal to Pixel.                         */
  589.         if (EGifCompressOutput(Private, CrntCode)
  590.         == ERROR) {
  591.         _GifError = E_GIF_ERR_DiskIsFull;
  592.         return ERROR;
  593.         }
  594.         CrntCode = Pixel;
  595.  
  596.         /* If however the HashTable if full, we send a clear first and   */
  597.         /* Clear the hash table.                         */
  598.         if (Private -> RunningCode >= ZL_MAX_CODE) {
  599.         /* Time to do some clearance: */
  600.         if (EGifCompressOutput(Private, Private -> ClearCode)
  601.             == ERROR) {
  602.             _GifError = E_GIF_ERR_DiskIsFull;
  603.             return ERROR;
  604.         }
  605.         Private -> RunningCode = Private -> EOFCode + 1;
  606.         Private -> RunningBits = Private -> BitsPerPixel + 1;
  607.         Private -> MaxCode1 = 1 << Private -> RunningBits;
  608.         _ClearHashTable(HashTable);
  609.         }
  610.         else {
  611.         /* Put this unique key with its relative Code in hash table: */
  612.         _InsertHashTable(HashTable, NewKey, Private -> RunningCode++);
  613.         }
  614.     }
  615.     }
  616.  
  617.     /* Preserve the current state of the compression algorithm: */
  618.     Private -> CrntCode = CrntCode;
  619.  
  620.     if (Private -> PixelCount == 0)
  621.     {
  622.     /* We are done - output last Code and flush output buffers: */
  623.     if (EGifCompressOutput(Private, CrntCode)
  624.         == ERROR) {
  625.         _GifError = E_GIF_ERR_DiskIsFull;
  626.         return ERROR;
  627.     }
  628.     if (EGifCompressOutput(Private, Private -> EOFCode)
  629.         == ERROR) {
  630.         _GifError = E_GIF_ERR_DiskIsFull;
  631.         return ERROR;
  632.     }
  633.     if (EGifCompressOutput(Private, FLUSH_OUTPUT) == ERROR) {
  634.         _GifError = E_GIF_ERR_DiskIsFull;
  635.         return ERROR;
  636.     }
  637.     }
  638.  
  639.     return OK;
  640. }
  641.  
  642. /******************************************************************************
  643. *   The LZ compression output routine:                          *
  644. *   This routine is responsable for the compression of the bit stream into    *
  645. * 8 bits (bytes) packets.                              *
  646. *   Returns OK if written succesfully.                          *
  647. ******************************************************************************/
  648. static int EGifCompressOutput(GifFilePrivateType *Private, int Code)
  649. {
  650.     int retval = OK;
  651.  
  652.     if (Code == FLUSH_OUTPUT) {
  653.     while (Private -> CrntShiftState > 0) {
  654.         /* Get Rid of what is left in DWord, and flush it */
  655.         if (EGifBufferedOutput(Private -> File, Private -> Buf,
  656.         Private -> CrntShiftDWord & 0xff) == ERROR) retval = ERROR;
  657.         Private -> CrntShiftDWord >>= 8;
  658.         Private -> CrntShiftState -= 8;
  659.     }
  660.     Private -> CrntShiftState = 0;                /* For next time */
  661.     if (EGifBufferedOutput(Private -> File, Private -> Buf,
  662.         FLUSH_OUTPUT) == ERROR) retval = ERROR;
  663.     }
  664.     else {
  665.     Private -> CrntShiftDWord |= ((long) Code) << Private -> CrntShiftState;
  666.     Private -> CrntShiftState += Private -> RunningBits;
  667.     while (Private -> CrntShiftState >= 8) {
  668.         /* Dump out full bytes: */
  669.         if (EGifBufferedOutput(Private -> File, Private -> Buf,
  670.         Private -> CrntShiftDWord & 0xff) == ERROR) retval = ERROR;
  671.         Private -> CrntShiftDWord >>= 8;
  672.         Private -> CrntShiftState -= 8;
  673.     }
  674.     }
  675.  
  676.     /* If code cannt fit into RunningBits bits, must raise its size. Note */
  677.     /* however that codes above 4095 are used for special signaling.      */
  678.     if (Private -> RunningCode >= Private -> MaxCode1 && Code <= 4095) {
  679.     Private -> MaxCode1 = 1 << ++Private -> RunningBits;
  680.     }
  681.  
  682.     return retval;
  683. }
  684.  
  685. /******************************************************************************
  686. *   This routines buffers the given characters until 255 characters are ready *
  687. * to be output. If Code is equal to -1 the buffer is flushed (EOF).          *
  688. *   The buffer is Dumped with first byte as its size, as GIF format requires. *
  689. *   Returns OK if written succesfully.                          *
  690. ******************************************************************************/
  691. static int EGifBufferedOutput(FILE *File, ByteType *Buf, int c)
  692. {
  693.     if (c == FLUSH_OUTPUT) {
  694.     /* Flush everything out */
  695.     if (Buf[0] != 0 && fwrite(Buf, 1, Buf[0]+1, File) != Buf[0] + 1)
  696.     {
  697.         _GifError = E_GIF_ERR_WriteFailed;
  698.         return ERROR;
  699.     }
  700.     /* Mark end of compressed data, by an empty block (see GIF doc): */
  701.     Buf[0] = 0;
  702.     if (fwrite(Buf, 1, 1, File) != 1)
  703.     {
  704.         _GifError = E_GIF_ERR_WriteFailed;
  705.         return ERROR;
  706.     }
  707.     }
  708.     else {
  709.     if (Buf[0] == 255) {
  710.         /* Dump out this buffer - it is full: */
  711.         if (fwrite(Buf, 1, Buf[0] + 1, File) != Buf[0] + 1)
  712.         {
  713.         _GifError = E_GIF_ERR_WriteFailed;
  714.         return ERROR;
  715.         }
  716.         Buf[0] = 0;
  717.     }
  718.     Buf[++Buf[0]] = c;
  719.     }
  720.  
  721.     return OK;
  722. }
  723.