home *** CD-ROM | disk | FTP | other *** search
/ Collection of Hack-Phreak Scene Programs / cleanhpvac.zip / cleanhpvac / TIERRA40.ZIP / BEAGLE / GIF / EGIF_LIB.C < prev    next >
C/C++ Source or Header  |  1992-05-02  |  26KB  |  771 lines

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