home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / GRAPHICS / MISC / PVQUAN15.ZIP / GIFLIB.ZIP / EGIF_LIB.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-09  |  14.0 KB  |  373 lines

  1. /************************************************************************
  2.  *                                                                      *
  3.  *                  Copyright (c) 1991, Frank van der Hulst             *
  4.  *                          All Rights Reserved                         *
  5.  *                                                                      *
  6.  * Authors:                                                             *
  7.  *        FvdH - Frank van der Hulst (Wellington, NZ)                   *
  8.  *                                                                      *
  9.  * Versions:                                                            *
  10.  *      V1.1 910626 FvdH - QUANT released for DBW_RENDER                *
  11.  *      V1.2 911021 FvdH - QUANT released for PoV Ray                   *
  12.  *      V1.4 920303 FvdH - Ported to GNU                                *
  13.  *                                                                      *
  14.  ************************************************************************/
  15. /******************************************************************
  16. *   "Gif-Lib" - Yet another gif library.                                  *
  17. *                                                                                      *
  18. * Written by:  Gershon Elber                Ver 1.1, Aug. 1990           *
  19. *******************************************************************
  20. * The kernel of the GIF Encoding process can be found here.            *
  21. *******************************************************************
  22. * History:                                                                          *
  23. * 14 Jun 89 - Version 1.0 by Gershon Elber.                              *
  24. *  3 Sep 90 - Version 1.1 by Gershon Elber (Gif89, Unique names). *
  25. *******************************************************************/
  26.  
  27. #include <string.h>
  28.  
  29. #ifdef __TURBOC__
  30. #include <alloc.h>
  31. #endif
  32.  
  33. #include "gif_lib.h"
  34. #include "gif_hash.h"
  35.  
  36. #define    TRUE    1
  37. #define    FALSE    0
  38.  
  39. #define FLUSH_OUTPUT        4096    /* Impossible code, to signal flush. */
  40. #define FIRST_CODE        4097    /* Impossible code, to signal first. */
  41.  
  42. #define RED        0
  43. #define GREEN    1
  44. #define BLUE    2
  45.  
  46. static int    Private_BitsPerPixel;            /* Bits per pixel (Codes uses at list this + 1). */
  47. static unsigned long Private_PixelCount;
  48. static unsigned char Private_Buf[256];                          /* Compressed output is buffered here. */
  49. static int Private_ClearCode;                       /* The CLEAR LZ code. */
  50. static int Private_EOFCode;                            /* The EOF LZ code. */
  51. static int Private_RunningCode;                   /* The next code algorithm can generate. */
  52. static int Private_RunningBits;                    /* The number of bits required to represent RunningCode. */
  53. static int Private_MaxCode1;                        /* 1 bigger than max. possible code, in RunningBits bits. */
  54. static int Private_CrntCode;                        /* Current algorithm code. */
  55. static int Private_CrntShiftState;                /* Number of bits in CrntShiftDWord. */
  56. static unsigned long Private_CrntShiftDWord;  /* For bytes decomposition into codes. */
  57.  
  58. static int Gif_SBitsPerPixel;                         /* How many colors can we generate? */
  59.  
  60. /* Masks given codes to BitsPerPixel, to make sure all codes are in range: */
  61. static char CodeMask[] = {
  62.     0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
  63. };
  64.  
  65. static unsigned long *hash_table;
  66. FILE *GIF_file;
  67.  
  68. static char *GifVersionPrefix = "GIF87a";
  69.  
  70. static void    EGifPutWord(int Word);
  71. static void    EGifSetupCompress(void);
  72. static int EGifCompressLine(unsigned char *Line, int LineLen);
  73. static int EGifCompressOutput(int Code);
  74. static int EGifBufferedOutput(unsigned char *Buf, int c);
  75.  
  76. /******************************************************************************
  77. *   Open a new gif file for write, given by its name. If TestExistance then   *
  78. * if the file exists this routines fails (returns NULL).              *
  79. *   Returns GifFileType pointer dynamically allocated which serves as the gif *
  80. * info record. _GifError is cleared if succesfull.                  *
  81. ******************************************************************************/
  82. int EGifOpenFileName(char *FileName)
  83. {
  84.     GIF_file = fopen(FileName, "wb");
  85.     if (GIF_file == NULL) {
  86.         printf("EGIF Error: OPEN FAILED");
  87.         return -1;
  88.     }
  89.  
  90.     if (fwrite(GifVersionPrefix, 1, strlen(GifVersionPrefix), GIF_file) !=
  91.                         strlen(GifVersionPrefix)) {
  92.         printf("EGIF Error: WRITE FAILED");
  93.         return -1;
  94.     }
  95.  
  96.     if ((hash_table = (unsigned long *) malloc(sizeof(long) * HT_SIZE)) == NULL) {
  97.         printf("GIF Error: Not enough memory");
  98.         return -1;
  99.     }
  100.     HashTable_Clear(hash_table);
  101.  
  102.     return 0;
  103. }
  104.  
  105. /******************************************************************************
  106. *   This routine should be called before any other EGif calls, immediately    *
  107. * follows the GIF file openning.                          *
  108. ******************************************************************************/
  109. void EGifPutScreenDesc(int Width, int Height, int ColorRes, int BackGround,
  110.     int BitsPerPixel, unsigned char ColorMap[][3])
  111. {
  112. int i;
  113.  
  114.     Gif_SBitsPerPixel = BitsPerPixel;
  115.  
  116.     /* Put the screen descriptor into the file: */
  117.     EGifPutWord(Width);
  118.     EGifPutWord(Height);
  119.     putc(0x80 | ((ColorRes - 1) << 4) | (BitsPerPixel - 1), GIF_file);
  120.     putc(BackGround, GIF_file);
  121.     putc(0, GIF_file);
  122.  
  123.     /* If we have Global color map - dump it also: */
  124.     for (i = 0; i < (1 << BitsPerPixel); i++) {
  125.         /* Put the ColorMap out also: */
  126.         putc(ColorMap[i][RED]   << (8 - ColorRes), GIF_file);
  127.         putc(ColorMap[i][GREEN] << (8 - ColorRes), GIF_file);
  128.         putc(ColorMap[i][BLUE]  << (8 - ColorRes), GIF_file);
  129.     }
  130. }
  131.  
  132. /******************************************************************************
  133. *   This routine should be called before any attemp to dump an image - any    *
  134. * call to any of the pixel dump routines.                      *
  135. ******************************************************************************/
  136. void EGifPutImageDesc(int Left, int Top, int Width, int Height, int BitsPerPixel)
  137. {
  138.     /* Put the image descriptor into the file: */
  139.      putc(',', GIF_file);
  140.      EGifPutWord(Left);
  141.      EGifPutWord(Top);
  142.      EGifPutWord(Width);
  143.      EGifPutWord(Height);
  144.      putc(BitsPerPixel - 1, GIF_file);
  145.  
  146.     Private_PixelCount = (long) Width * (long) Height;
  147.  
  148.      EGifSetupCompress();      /* Reset compress algorithm parameters. */
  149. }
  150.  
  151. /******************************************************************************
  152. *  Put one full scanned line (Line) of length LineLen into GIF file.          *
  153. ******************************************************************************/
  154. int EGifPutLine(unsigned char *Line, int LineLen)
  155. {
  156.     int i;
  157.     char Mask;
  158.  
  159.     if ((Private_PixelCount -= LineLen) < 0) {
  160.     printf("E_GIF_ERR_DATA_TOO_BIG");
  161.     return TRUE;
  162.     }
  163.  
  164.     /* Make sure the codes are not out of bit range, as we might generate    */
  165.     /* wrong code (because of overflow when we combine them) in this case:   */
  166.     Mask = CodeMask[Private_BitsPerPixel];
  167.     for (i = 0; i < LineLen; i++) Line[i] &= Mask;
  168.  
  169.      return EGifCompressLine(Line, LineLen);
  170. }
  171.  
  172. /******************************************************************************
  173. *   This routine should be called last, to close GIF file.              *
  174. ******************************************************************************/
  175. void EGifCloseFile(void)
  176. {
  177.     putc(';', GIF_file);
  178.  
  179.     if (hash_table) free(hash_table);
  180.  
  181.     if (fclose(GIF_file) != 0) printf("E_GIF_ERR_CLOSE_FAILED");
  182. }
  183.  
  184. /******************************************************************************
  185. *   Put 2 bytes (word) into the given file:                      *
  186. ******************************************************************************/
  187. static void EGifPutWord(int Word)
  188. {
  189. char c[2];
  190.  
  191.     c[0] = Word & 0xff;
  192.     c[1] = (Word >> 8) & 0xff;
  193.     fwrite(c, 1, 2, GIF_file);
  194. }
  195.  
  196. /******************************************************************************
  197. *   Setup the LZ compression for this image:                      *
  198. ******************************************************************************/
  199. static void EGifSetupCompress(void)
  200. {
  201.     int BitsPerPixel;
  202.     char Buf;
  203.  
  204.     /* Test and see what color map to use, and from it # bits per pixel: */
  205.     BitsPerPixel = Gif_SBitsPerPixel;
  206.  
  207.     Buf = BitsPerPixel = (BitsPerPixel < 2 ? 2 : BitsPerPixel);
  208.     fwrite(&Buf, 1, 1, GIF_file);     /* Write the Code size to file. */
  209.  
  210.     Private_Buf[0] = 0;              /* Nothing was output yet. */
  211.     Private_BitsPerPixel = BitsPerPixel;
  212.     Private_ClearCode = (1 << BitsPerPixel);
  213.     Private_EOFCode = Private_ClearCode + 1;
  214.     Private_RunningCode = Private_EOFCode + 1;
  215.     Private_RunningBits = BitsPerPixel + 1;     /* Number of bits per code. */
  216.     Private_MaxCode1 = 1 << Private_RunningBits;       /* Max. code + 1. */
  217.     Private_CrntCode = FIRST_CODE;       /* Signal that this is first one! */
  218.     Private_CrntShiftState = 0;      /* No information in CrntShiftDWord. */
  219.     Private_CrntShiftDWord = 0;
  220.  
  221.     /* Clear hash table and send Clear to make sure the decoder do the same. */
  222.      HashTable_Clear(hash_table);
  223.     if (EGifCompressOutput(Private_ClearCode)) printf("E_GIF_ERR_DISK_IS_FULL");
  224. }
  225.  
  226. /******************************************************************************
  227. *   The LZ compression routine:                              *
  228. *   This version compress the given buffer Line of length LineLen.          *
  229. *   This routine can be called few times (one per scan line, for example), in *
  230. * order the complete the whole image.                          *
  231. ******************************************************************************/
  232. static int EGifCompressLine(unsigned char *Line, int LineLen)
  233. {
  234. int i = 0, CrntCode, NewCode;
  235. unsigned long NewKey;
  236. unsigned char Pixel;
  237.  
  238.     if (Private_CrntCode == FIRST_CODE)          /* Its first time! */
  239.         CrntCode = Line[i++];
  240.     else CrntCode = Private_CrntCode;     /* Get last code in compression. */
  241.  
  242.     while (i < LineLen) {                /* Decode LineLen items. */
  243.         Pixel = Line[i++];              /* Get next pixel from stream. */
  244.     /* Form a new unique key to search hash table for the code combines  */
  245.     /* CrntCode as Prefix string with Pixel as postfix char.         */
  246.         NewKey = (((unsigned long) CrntCode) << 8) + Pixel;
  247.         if ((NewCode = HashTable_Exists(hash_table, NewKey)) >= 0) {
  248.         /* This Key is already there, or the string is old one, so         */
  249.         /* simple take new code as our CrntCode:                 */
  250.             CrntCode = NewCode;
  251.         } else {
  252.         /* Put it in hash table, output the prefix code, and make our    */
  253.         /* CrntCode equal to Pixel.                         */
  254.             if (EGifCompressOutput(CrntCode)) {
  255.                 printf("E_GIF_ERR_DISK_IS_FULL");
  256.                 return TRUE;
  257.             }
  258.             CrntCode = Pixel;
  259.  
  260.         /* If however the HashTable if full, we send a clear first and   */
  261.         /* Clear the hash table.                         */
  262.             if (Private_RunningCode >= ZL_MAX_CODE) {
  263.         /* Time to do some clearance: */
  264.                 if (EGifCompressOutput(Private_ClearCode)) {
  265.                     printf("E_GIF_ERR_DISK_IS_FULL");
  266.                     return TRUE;
  267.                 }
  268.                 Private_RunningCode = Private_EOFCode + 1;
  269.                 Private_RunningBits = Private_BitsPerPixel + 1;
  270.                 Private_MaxCode1 = 1 << Private_RunningBits;
  271.                 HashTable_Clear(hash_table);
  272.             } else {
  273.         /* Put this unique key with its relative Code in hash table: */
  274.                 HashTable_Insert(hash_table, NewKey, Private_RunningCode++);
  275.             }
  276.         }
  277.     }
  278.  
  279.     /* Preserve the current state of the compression algorithm: */
  280.     Private_CrntCode = CrntCode;
  281.  
  282.     if (Private_PixelCount == 0) {
  283.     /* We are done - output last Code and flush output buffers: */
  284.         if (EGifCompressOutput(CrntCode)) {
  285.             printf("E_GIF_ERR_DISK_IS_FULL");
  286.             return TRUE;
  287.         }
  288.         if (EGifCompressOutput(Private_EOFCode)) {
  289.             printf("E_GIF_ERR_DISK_IS_FULL");
  290.             return TRUE;
  291.         }
  292.         if (EGifCompressOutput(FLUSH_OUTPUT)) {
  293.             printf("E_GIF_ERR_DISK_IS_FULL");
  294.             return TRUE;
  295.         }
  296.     }
  297.  
  298.     return FALSE;
  299. }
  300.  
  301. /******************************************************************************
  302. *   The LZ compression output routine:                          *
  303. *   This routine is responsable for the compression of the bit stream into    *
  304. * 8 bits (bytes) packets.                              *
  305. *   Returns GIF_OK if written succesfully.                      *
  306. ******************************************************************************/
  307. static int EGifCompressOutput(int Code)
  308. {
  309. int retval = FALSE;
  310.  
  311.     if (Code == FLUSH_OUTPUT) {
  312.         while (Private_CrntShiftState > 0) {
  313.         /* Get Rid of what is left in DWord, and flush it. */
  314.             if (EGifBufferedOutput(Private_Buf,    (int)(Private_CrntShiftDWord) & 0xff))
  315.                 retval = TRUE;
  316.             Private_CrntShiftDWord >>= 8;
  317.             Private_CrntShiftState -= 8;
  318.         }
  319.         Private_CrntShiftState = 0;               /* For next time. */
  320.         if (EGifBufferedOutput(Private_Buf, FLUSH_OUTPUT))
  321.             retval = TRUE;
  322.      } else {
  323.         Private_CrntShiftDWord |= ((long) Code) << Private_CrntShiftState;
  324.         Private_CrntShiftState += Private_RunningBits;
  325.         while (Private_CrntShiftState >= 8) {
  326.         /* Dump out full bytes: */
  327.             if (EGifBufferedOutput(Private_Buf,    (int)(Private_CrntShiftDWord) & 0xff))
  328.                 retval = TRUE;
  329.             Private_CrntShiftDWord >>= 8;
  330.             Private_CrntShiftState -= 8;
  331.         }
  332.     }
  333.  
  334.     /* If code cannt fit into RunningBits bits, must raise its size. Note */
  335.     /* however that codes above 4095 are used for special signaling.      */
  336.     if (Private_RunningCode >= Private_MaxCode1 && Code <= 4095) {
  337.         Private_MaxCode1 = 1 << ++Private_RunningBits;
  338.     }
  339.  
  340.     return retval;
  341. }
  342.  
  343. /******************************************************************************
  344. *   This routines buffers the given characters until 255 characters are ready *
  345. * to be output. If Code is equal to -1 the buffer is flushed (EOF).          *
  346. *   The buffer is Dumped with first byte as its size, as GIF format requires. *
  347. *   Returns GIF_OK if written succesfully.                      *
  348. ******************************************************************************/
  349. static int EGifBufferedOutput(unsigned char *Buf, int c)
  350. {
  351.     if (c == FLUSH_OUTPUT) {
  352.     /* Flush everything out. */
  353.         if (Buf[0] != 0 && fwrite(Buf, 1, Buf[0]+1, GIF_file) != Buf[0] + 1)    {
  354.             printf("E_GIF_ERR_WRITE_FAILED");
  355.             return TRUE;
  356.         }
  357.     /* Mark end of compressed data, by an empty block (see GIF doc): */
  358.         putc(0, GIF_file);
  359.     } else {
  360.         if (Buf[0] == 255) {
  361.         /* Dump out this buffer - it is full: */
  362.             if (fwrite(Buf, 1, Buf[0] + 1, GIF_file) != Buf[0] + 1) {
  363.                 printf("E_GIF_ERR_WRITE_FAILED");
  364.                 return TRUE;
  365.             }
  366.             Buf[0] = 0;
  367.         }
  368.         Buf[++Buf[0]] = c;
  369.     }
  370.  
  371.     return FALSE;
  372. }
  373.