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