GIFSAVE.C
上传用户:sunrenlu
上传日期:2022-06-13
资源大小:1419k
文件大小:20k
源码类别:

操作系统开发

开发平台:

DOS

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <rtos.h>
  4. #include <net.h>
  5. #include <mem.h>
  6. #include "gifsave.h"
  7. typedef unsigned short Word;
  8. typedef unsigned char Byte;
  9. /*
  10.  * I/O Routines
  11.  */
  12. static tcp_Socket *OutSocket;
  13. void *imghandle = NULL;
  14. /*
  15.  * Routines to write a bit-file
  16.  */
  17. static Byte Buffer[256];        /* There must be one byte to many  */
  18. static int  Index,              /* Current byte in buffer */
  19.             BitsLeft;           /* Bits left to fill in current byte. These
  20.                                 /* are right-justified */
  21. /*
  22.  * Routines to maintain an LZW-string table
  23.  */
  24. #define RES_CODES 2
  25. #define HASH_FREE 0xFFFF
  26. #define NEXT_FIRST 0xFFFF
  27. #define MAXBITS 12
  28. #define MAXSTR (1 << MAXBITS)
  29. #define HASHSIZE 9973
  30. #define HASHSTEP 2039
  31. #define HASH(index, lastbyte) (((lastbyte << 8) ^ index) % HASHSIZE)
  32. static Byte *StrChr = NULL;
  33. static Word *StrNxt = NULL,
  34.             *StrHsh = NULL,
  35.             NumStrings;
  36. /*
  37.  * Main routines
  38.  */
  39. typedef struct {
  40.     Word LocalScreenWidth,
  41.          LocalScreenHeight;
  42.     Byte GlobalColorTableSize : 3,
  43.          SortFlag             : 1,
  44.          ColorResolution      : 3,
  45.          GlobalColorTableFlag : 1;
  46.     Byte BackgroundColorIndex;
  47.     Byte PixelAspectRatio;
  48. } ScreenDescriptor;
  49. typedef struct {
  50.     Byte Separator;
  51.     Word LeftPosition,
  52.          TopPosition;
  53.     Word Width,
  54.          Height;
  55.     Byte LocalColorTableSize : 3,
  56.          Reserved            : 2,
  57.          SortFlag            : 1,
  58.          InterlaceFlag       : 1,
  59.          LocalColorTableFlag : 1;
  60. } ImageDescriptor;
  61. static int  BitsPrPrimColor,    /* Bits pr primary color */
  62.             NumColors;          /* Number of colors in color table */
  63. static Byte *ColorTable = NULL;
  64. static Word ScreenHeight,
  65.             ScreenWidth,
  66.             ImageHeight,
  67.             ImageWidth,
  68.             ImageLeft,
  69.             ImageTop,
  70.             RelPixX, RelPixY;         /* Used by InputByte() -function */
  71. static int  (*GetPixel)(void *p, int x, int y);
  72. /*
  73.  * Private Functions
  74.  */
  75. /*
  76.  * Routines to do file IO
  77.  */
  78. static int Create(char *socket)
  79. {
  80.     OutSocket = socket;
  81.     return GIF_OK;
  82. }
  83. static int WriteBufPlusLen( void *buf, int len )
  84. {
  85.     BYTE *s;
  86.     s = kcalloc( len + 1, 1 );
  87.     if (s != NULL ) {
  88.         *s = len;
  89.         memcpy( s+1, buf, len );
  90.         sock_write( OutSocket, s, len + 1 );
  91.         kfree( s );
  92.     }
  93.     return GIF_OK;
  94. }
  95. static int Write(void *buf, unsigned len)
  96. {
  97.     sock_write( OutSocket, buf, len );
  98.     return GIF_OK;
  99. }
  100. static int WriteByte(Byte b)
  101. {
  102.     sock_write( OutSocket, &b, 1 );
  103.     return GIF_OK;
  104. }
  105. static int WriteWord(Word w)
  106. {
  107.     sock_write( OutSocket, &w, 2 );
  108.     return GIF_OK;
  109. }
  110. static void Close(void)
  111. {
  112.     OutSocket = NULL;
  113. }
  114. /*
  115.  * Routines to write a bit-file
  116.  */
  117. /*
  118.  *  InitBitFile()
  119.  *
  120.  *  Initiate for using a bitfile. All output is sent to
  121.  *  the current OutFile using the I/O-routines above.
  122.  *
  123.  */
  124. static void InitBitFile(void)
  125. {
  126.     Buffer[Index = 0] = 0;
  127.     BitsLeft = 8;
  128. }
  129. /*
  130.  *  ResetOutBitFile()
  131.  *
  132.  *  Tidy up after using a bitfile
  133.  *
  134.  */
  135. static int ResetOutBitFile(void)
  136. {
  137.     Byte numbytes;
  138.     /*
  139.      *  Find out how much is in the buffer
  140.      */
  141.     numbytes = Index + (BitsLeft == 8 ? 0 : 1);
  142.     /*
  143.      *  Write whatever is in the buffer to the file
  144.      */
  145.     if (numbytes) {
  146. /*
  147.         if (WriteByte(numbytes) != GIF_OK)
  148.             return -1;
  149.         if (Write(Buffer, numbytes) != GIF_OK)
  150.             return -1;
  151. */
  152.         if ( WriteBufPlusLen( Buffer, numbytes ) != GIF_OK )
  153.             return -1 ;
  154.         Buffer[Index = 0] = 0;
  155.         BitsLeft = 8;
  156.     }
  157.     return 0;
  158. }
  159. /*
  160.  *  WriteBits()
  161.  *
  162.  *  Put the given number of bits to the outfile.
  163.  *
  164.  *  bits    - bits to write from (right justified)
  165.  *  numbits - number of bits to write
  166.  *
  167.  *  returns bits written, or -1 on error.
  168.  *
  169.  */
  170. static int WriteBits(int bits, int numbits)
  171. {
  172.     int  bitswritten = 0;
  173.     Byte numbytes = 255;
  174.     do {
  175.         /*
  176.          *  If the buffer is full, write it.
  177.          */
  178.         if ((Index == 254 && !BitsLeft) || Index > 254) {
  179. /*
  180.             if (WriteByte(numbytes) != GIF_OK)
  181.                 return -1;
  182.             if (Write(Buffer, numbytes) != GIF_OK)
  183.                 return -1;
  184. */
  185.             if (WriteBufPlusLen( Buffer, numbytes ) != GIF_OK )
  186.                 return -1;
  187.             Buffer[Index = 0] = 0;
  188.             BitsLeft = 8;
  189.         }
  190.         /*
  191.          *  Now take care of the two specialcases
  192.          */
  193.         if (numbits <= BitsLeft) {
  194.             Buffer[Index] |= (bits & ((1 << numbits) - 1)) << (8 - BitsLeft);
  195.             bitswritten += numbits;
  196.             BitsLeft -= numbits;
  197.             numbits = 0;
  198.         } else {
  199.             Buffer[Index] |= (bits & ((1 << BitsLeft) - 1)) << (8 - BitsLeft);
  200.             bitswritten += BitsLeft;
  201.             bits >>= BitsLeft;
  202.             numbits -= BitsLeft;
  203.             Buffer[++Index] = 0;
  204.             BitsLeft = 8;
  205.         }
  206.     } while (numbits);
  207.     return bitswritten;
  208. }
  209. /*
  210.  * Routines to maintain an LZW-string table
  211.  */
  212. void do_free( void *p )
  213. {
  214.     kfree( p );
  215. }
  216. void *do_malloc( int size )
  217. {
  218.     kcalloc( size, 1 );
  219. }
  220. /*
  221.  *  FreeStrtab()
  222.  *
  223.  *  Free arrays used in string table routines
  224.  *
  225.  */
  226. static void FreeStrtab(void)
  227. {
  228.     if (StrHsh) {
  229.         do_free(StrHsh);
  230.         StrHsh = NULL;
  231.     }
  232.     if (StrNxt) {
  233.         do_free(StrNxt);
  234.         StrNxt = NULL;
  235.     }
  236.     if (StrChr) {
  237.         do_free(StrChr);
  238.         StrChr = NULL;
  239.     }
  240. }
  241. /*
  242.  *  AllocStrtab()
  243.  *
  244.  *  Allocate arrays used in string table routines
  245.  *
  246.  */
  247. static int AllocStrtab(void)
  248. {
  249.     /*
  250.      *  Just in case . . .
  251.      */
  252.     FreeStrtab();
  253.     if ((StrChr = (Byte *) do_malloc(MAXSTR * sizeof(Byte))) == 0) {
  254.         FreeStrtab();
  255.         return GIF_OUTMEM;
  256.     }
  257.     if ((StrNxt = (Word *) do_malloc(MAXSTR * sizeof(Word))) == 0) {
  258.         FreeStrtab();
  259.         return GIF_OUTMEM;
  260.     }
  261.     if ((StrHsh = (Word *) do_malloc(HASHSIZE * sizeof(Word))) == 0) {
  262.         FreeStrtab();
  263.         return GIF_OUTMEM;
  264.     }
  265.     return GIF_OK;
  266. }
  267. /*
  268.  *  AddCharString()
  269.  *
  270.  *  Add a string consisting of the string of index plus the byte b.
  271.  *
  272.  *  If a string of length 1 is wanted, the index should be 0xFFFF.
  273.  *
  274.  *  index - Index to first part of string, or 0xFFFF is
  275.  *           only 1 byte is wanted
  276.  *  b     - Last byte in new string
  277.  *
  278.  *  returns index to new string, or 0xFFFF if no more room
  279.  *
  280.  */
  281. static Word AddCharString(Word index, Byte b)
  282. {
  283.     Word hshidx;
  284.     /*
  285.      *  Check if there is more room
  286.      */
  287.     if (NumStrings >= MAXSTR)
  288.         return 0xFFFF;
  289.     /*
  290.      *  Search the string table until a free position is found
  291.      */
  292.     hshidx = HASH(index, b);
  293.     while (StrHsh[hshidx] != 0xFFFF)
  294.         hshidx = (hshidx + HASHSTEP) % HASHSIZE;
  295.     /*
  296.      *  Insert new string
  297.      */
  298.     StrHsh[hshidx] = NumStrings;
  299.     StrChr[NumStrings] = b;
  300.     StrNxt[NumStrings] = (index != 0xFFFF) ? index : NEXT_FIRST;
  301.     return NumStrings++;
  302. }
  303. /*
  304.  *  FindCharString()
  305.  *
  306.  *  Find index of string consisting of the string of index plus the byte b.
  307.  *
  308.  *  If a string of length 1 is wanted, the index should be 0xFFFF.
  309.  *
  310.  *  index - Index to first part of string, or 0xFFFF is only 1 byte is wanted
  311.  *  b     - Last byte in string
  312.  *
  313.  *  returns index to string, or 0xFFFF if not found
  314.  *
  315.  */
  316. static Word FindCharString(Word index, Byte b)
  317. {
  318.     Word hshidx, nxtidx;
  319.     /*
  320.      *  Check if index is 0xFFFF. In that case we need only
  321.      *  return b, since all one-character strings has their
  322.      *  bytevalue as their index
  323.      */
  324.     if (index == 0xFFFF)
  325.         return b;
  326.     /*
  327.      *  Search the string table until the string is found, or
  328.      *  we find HASH_FREE. In that case the string does not
  329.      *  exist.
  330.      */
  331.     hshidx = HASH(index, b);
  332.     while ((nxtidx = StrHsh[hshidx]) != 0xFFFF) {
  333.         if (StrNxt[nxtidx] == index && StrChr[nxtidx] == b)
  334.             return nxtidx;
  335.         hshidx = (hshidx + HASHSTEP) % HASHSIZE;
  336.     }
  337.     /*
  338.      *  No match is found
  339.      */
  340.     return 0xFFFF;
  341. }
  342. /*
  343.  *  ClearStrtab()
  344.  *
  345.  *  Mark the entire table as free, enter the 2**codesize one-byte strings,
  346.  *  and reserve the RES_CODES reserved codes.
  347.  *
  348.  *  codesize - Number of bits to encode one pixel
  349.  *
  350.  */
  351. static void ClearStrtab(int codesize)
  352. {
  353.     int q, w;
  354.     Word *wp;
  355.     /*
  356.      *  No strings currently in the table
  357.      */
  358.     NumStrings = 0;
  359.     /*
  360.      *  Mark entire hashtable as free
  361.      */
  362.     wp = StrHsh;
  363.     for (q = 0; q < HASHSIZE; q++)
  364.         *wp++ = HASH_FREE;
  365.     /*
  366.      *  Insert 2**codesize one-character strings, and reserved codes
  367.      */
  368.     w = (1 << codesize) + RES_CODES;
  369.     for (q = 0; q < w; q++)
  370.         AddCharString(0xFFFF, q);
  371. }
  372. /*
  373.  * LZW compression routine
  374.  */
  375. /*
  376.  * LZW_Compress()
  377.  *
  378.  * Perform LZW compression as specified in the GIF-standard.
  379.  *
  380.  * codesize  - Number of bits needed to represent one pixelvalue.
  381.  * inputbyte - Function that fetches each byte to compress.
  382.  *             Must return -1 when no more bytes.
  383.  *
  384.  */
  385. static int LZW_Compress(int codesize, int (*inputbyte)(void))
  386. {
  387.     register int c;
  388.     register Word index;
  389.     int  clearcode, endofinfo, numbits, limit, errcode;
  390.     Word prefix = 0xFFFF;
  391.     /*
  392.      *  Set up the given outfile
  393.      */
  394.     InitBitFile();
  395.     /*
  396.      *  Set up variables and tables
  397.      */
  398.     clearcode = 1 << codesize;
  399.     endofinfo = clearcode + 1;
  400.     numbits = codesize + 1;
  401.     limit = (1 << numbits) - 1;
  402.     if ((errcode = AllocStrtab()) != GIF_OK)
  403.         return errcode;
  404.     ClearStrtab(codesize);
  405.     /*
  406.      *  First send a code telling the unpacker to clear the stringtable.
  407.      */
  408.     WriteBits(clearcode, numbits);
  409.     /*
  410.      *  Pack image
  411.      */
  412.     while ((c = inputbyte()) != -1) {
  413.         /*
  414.          *  Now perform the packing.
  415.          *  Check if the prefix + the new character is a string that
  416.          *  exists in the table
  417.          */
  418.         if ((index = FindCharString(prefix, c)) != 0xFFFF) {
  419.             /*
  420.              *  The string exists in the table.
  421.              *  Make this string the new prefix.
  422.              */
  423.             prefix = index;
  424.         } else {
  425.             /*
  426.              *  The string does not exist in the table.
  427.              *  First write code of the old prefix to the file.
  428.              */
  429.             WriteBits(prefix, numbits);
  430.             /*
  431.              *  Add the new string (the prefix + the new character)
  432.              *  to the stringtable.
  433.              */
  434.             if (AddCharString(prefix, c) > limit) {
  435.                 if (++numbits > 12) {
  436.                     WriteBits(clearcode, numbits - 1);
  437.                     ClearStrtab(codesize);
  438.                     numbits = codesize + 1;
  439.                 }
  440.                 limit = (1 << numbits) - 1;
  441.             }
  442.             /*
  443.              *  Set prefix to a string containing only the character
  444.              *  read. Since all possible one-character strings exists
  445.              *  int the table, there's no need to check if it is found.
  446.              */
  447.             prefix = c;
  448.         }
  449.     }
  450.     /*
  451.      *  End of info is reached. Write last prefix.
  452.      */
  453.     if (prefix != 0xFFFF)
  454.         WriteBits(prefix, numbits);
  455.     /*
  456.      *  Write end of info -mark.
  457.      */
  458.     WriteBits(endofinfo, numbits);
  459.     /*
  460.      *  Flush the buffer
  461.      */
  462.     ResetOutBitFile();
  463.     /*
  464.      *  Tidy up
  465.      */
  466.     FreeStrtab();
  467.     return GIF_OK;
  468. }
  469. /*
  470.  * Other routines
  471.  */
  472. /*
  473.  *  BitsNeeded()
  474.  *
  475.  *  Calculates number of bits needed to store numbers between 0 and n - 1
  476.  *
  477.  *  n - Number of numbers to store (0 to n - 1)
  478.  *
  479.  *  returns number of bits needed
  480.  *
  481.  */
  482. static int BitsNeeded(Word n)
  483. {
  484.     int ret = 1;
  485.     if (!n--)
  486.         return 0;
  487.     while (n >>= 1)
  488.         ++ret;
  489.     return ret;
  490. }
  491. /*
  492.  *  InputByte()
  493.  *
  494.  *  Get next pixel from image. Called by the LZW_Compress()-function
  495.  *
  496.  *  RETURNS Next pixelvalue, or -1 if no more pixels
  497.  *
  498.  */
  499. static int InputByte(void)
  500. {
  501.     int ret;
  502.     if (RelPixY >= ImageHeight)
  503.         return -1;
  504.     ret = GetPixel(imghandle, ImageLeft + RelPixX, ImageHeight - (ImageTop + RelPixY));
  505.     if (++RelPixX >= ImageWidth) {
  506.         RelPixX = 0;
  507.         ++RelPixY;
  508.     }
  509.     return ret;
  510. }
  511. /*
  512.  * WriteScreenDescriptor()
  513.  *
  514.  * Output a screen descriptor to the current GIF-file
  515.  *
  516.  * sd - Pointer to screen descriptor to output
  517.  *
  518.  */
  519. static int WriteScreenDescriptor(ScreenDescriptor *sd)
  520. {
  521.     Byte tmp;
  522. typedef struct {
  523.     WORD    width;
  524.     WORD    height;
  525.     BYTE    colorstuff;
  526.     BYTE    background;
  527.     BYTE    aspect;
  528. } hdr;
  529.     hdr h;
  530.     h.width = sd->LocalScreenWidth;
  531.     h.height = sd->LocalScreenHeight;
  532.     h.colorstuff = (sd->GlobalColorTableFlag << 7)
  533.           | (sd->ColorResolution << 4)
  534.           | (sd->SortFlag << 3)
  535.           | sd->GlobalColorTableSize;
  536.     h.background = sd->BackgroundColorIndex;
  537.     h.aspect = sd->PixelAspectRatio;
  538.     Write( &h, sizeof( h ));
  539. /*
  540.     if (WriteWord(sd->LocalScreenWidth) != GIF_OK)
  541.         return GIF_ERRWRITE;
  542.     if (WriteWord(sd->LocalScreenHeight) != GIF_OK)
  543.         return GIF_ERRWRITE;
  544.     tmp = (sd->GlobalColorTableFlag << 7)
  545.           | (sd->ColorResolution << 4)
  546.           | (sd->SortFlag << 3)
  547.           | sd->GlobalColorTableSize;
  548.     if (WriteByte(tmp) != GIF_OK)
  549.         return GIF_ERRWRITE;
  550.     if (WriteByte(sd->BackgroundColorIndex) != GIF_OK)
  551.         return GIF_ERRWRITE;
  552.     if (WriteByte(sd->PixelAspectRatio) != GIF_OK)
  553.         return GIF_ERRWRITE;
  554. */
  555.     return GIF_OK;
  556. }
  557. /*
  558.  * WriteImageDescriptor()
  559.  *
  560.  * Output an image descriptor to the current GIF-file
  561.  *
  562.  * id - Pointer to image descriptor to output
  563.  *
  564.  */
  565. static int WriteImageDescriptor(ImageDescriptor *id)
  566. {
  567.     Byte tmp;
  568.     if (WriteByte(id->Separator) != GIF_OK)
  569.         return GIF_ERRWRITE;
  570.     if (WriteWord(id->LeftPosition) != GIF_OK)
  571.         return GIF_ERRWRITE;
  572.     if (WriteWord(id->TopPosition) != GIF_OK)
  573.         return GIF_ERRWRITE;
  574.     if (WriteWord(id->Width) != GIF_OK)
  575.         return GIF_ERRWRITE;
  576.     if (WriteWord(id->Height) != GIF_OK)
  577.         return GIF_ERRWRITE;
  578.     tmp = (id->LocalColorTableFlag << 7)
  579.           | (id->InterlaceFlag << 6)
  580.           | (id->SortFlag << 5)
  581.           | (id->Reserved << 3)
  582.           | id->LocalColorTableSize;
  583.     if (WriteByte(tmp) != GIF_OK)
  584.         return GIF_ERRWRITE;
  585.     return GIF_OK;
  586. }
  587. /*
  588.  * Public Functions
  589.  */
  590. /*
  591.  *  GIF_Create()
  592.  *
  593.  *  Create a GIF-file, and write headers for both screen and image.
  594.  *
  595.  *  filename  - Name of file to create (including extension)
  596.  *  width     - Number of horisontal pixels on screen
  597.  *  height    - Number of vertical pixels on screen
  598.  *  numcolors - Number of colors in the colormaps
  599.  *  colorres  - Color resolution. Number of bits for each primary color
  600.  *
  601.  */
  602. int GIF_Create(tcp_Socket *socket, int width, int height,
  603.                int numcolors, int colorres)
  604. {
  605.     int q, tabsize;
  606.     Byte *bp;
  607.     ScreenDescriptor SD;
  608.     /*
  609.      *  Initiate variables for new GIF-file
  610.      */
  611.     NumColors = numcolors ? (1 << BitsNeeded(numcolors)) : 0;
  612.     BitsPrPrimColor = colorres;
  613.     ScreenHeight = height;
  614.     ScreenWidth = width;
  615.     /*
  616.      *  Create file specified
  617.      */
  618.     if (Create(socket) != GIF_OK)
  619.         return GIF_ERRCREATE;
  620.     /*
  621.      *  Write GIF signature
  622.      */
  623.     if ((Write("GIF87a", 6)) != GIF_OK)
  624.         return GIF_ERRWRITE;
  625.     /*
  626.      *  Initiate and write screen descriptor
  627.      */
  628.     SD.LocalScreenWidth = width;
  629.     SD.LocalScreenHeight = height;
  630.     if (NumColors) {
  631.         SD.GlobalColorTableSize = BitsNeeded(NumColors) - 1;
  632.         SD.GlobalColorTableFlag = 1;
  633.     } else {
  634.         SD.GlobalColorTableSize = 0;
  635.         SD.GlobalColorTableFlag = 0;
  636.     }
  637.     SD.SortFlag = 0;
  638.     SD.ColorResolution = colorres - 1;
  639.     SD.BackgroundColorIndex = 0;
  640.     SD.PixelAspectRatio = 0;
  641.     if (WriteScreenDescriptor(&SD) != GIF_OK)
  642.         return GIF_ERRWRITE;
  643.     /*
  644.      *  Allocate color table
  645.      */
  646.     if (ColorTable) {
  647.         do_free(ColorTable);
  648.         ColorTable = NULL;
  649.     }
  650.     if (NumColors) {
  651.         tabsize = NumColors * 3;
  652.         if ((ColorTable = (Byte *) do_malloc(tabsize * sizeof(Byte))) == NULL)
  653.             return GIF_OUTMEM;
  654.         else {
  655.             bp = ColorTable;
  656.             for (q = 0; q < tabsize; q++)
  657.                 *bp++ = 0;
  658.         }
  659.     }
  660.     return 0;
  661. }
  662. /*
  663.  *
  664.  *  GIF_SetColor()
  665.  *
  666.  *  Set red, green and blue components of one of the colors. The color
  667.  *  components are all in the range [0, (1 << BitsPrPrimColor) - 1]
  668.  *
  669.  *  colornum - Color number to set. [0, NumColors - 1]
  670.  *  red      - Red component of color
  671.  *  green    - Green component of color
  672.  *  blue     - Blue component of color
  673.  *
  674.  */
  675. void GIF_SetColor(int colornum, int red, int green, int blue)
  676. {
  677.     long maxcolor;
  678.     Byte *p;
  679.     maxcolor = (1L << BitsPrPrimColor) - 1L;
  680.     p = ColorTable + colornum * 3;
  681.     *p++ = (Byte) ((red * 255L) / maxcolor);
  682.     *p++ = (Byte) ((green * 255L) / maxcolor);
  683.     *p++ = (Byte) ((blue * 255L) / maxcolor);
  684. }
  685. /*
  686.  *
  687.  *  GIF_CompressImage()
  688.  *
  689.  *  Compress an image into the GIF-file previousely created using GIF_Create().
  690.  *  All color values should have been specified before this function is called.
  691.  *
  692.  * The pixels are retrieved using a user defined callback
  693.  * function. This function should accept two parameters,
  694.  * x and y, specifying which pixel to retrieve. The pixel
  695.  * values sent to this function are as follows:
  696.  *
  697.  * x : [ImageLeft, ImageLeft + ImageWidth - 1]
  698.  * y : [ImageTop, ImageTop + ImageHeight - 1]
  699.  *
  700.  * The function should return the pixel value for the
  701.  * point given, in the interval [0, NumColors - 1]
  702.  *
  703.  *  left     - Screen-relative leftmost pixel x-coordinate
  704.  *             of the image
  705.  *  top      - Screen-relative uppermost pixel y-coordinate
  706.  *             of the image
  707.  *  width    - Width of the image, or -1 if as wide as
  708.  *             the screen
  709.  *  height   - Height of the image, or -1 if as high as
  710.  *             the screen
  711.  *  getpixel - Address of user defined callback function.
  712.  *             (See above)
  713.  */
  714. int GIF_CompressImage(void *handle, int left, int top, int width, int height,
  715.                       int (*getpixel)(void *p, int x, int y))
  716. {
  717.     int codesize, errcode;
  718.     ImageDescriptor ID;
  719.     if (width < 0) {
  720.         width = ScreenWidth;
  721.         left = 0;
  722.     }
  723.     if (height < 0) {
  724.         height = ScreenHeight;
  725.         top = 0;
  726.     }
  727.     if (left < 0)
  728.         left = 0;
  729.     if (top < 0)
  730.         top = 0;
  731.     /*
  732.      *  Write global colortable if any
  733.      */
  734.     if (NumColors)
  735.         if ((Write(ColorTable, NumColors * 3)) != GIF_OK)
  736.             return GIF_ERRWRITE;
  737.     /*
  738.      *  Initiate and write image descriptor
  739.      */
  740.     ID.Separator = ',';
  741.     ID.LeftPosition = ImageLeft = left;
  742.     ID.TopPosition = ImageTop = top;
  743.     ID.Width = ImageWidth = width;
  744.     ID.Height = ImageHeight = height;
  745.     ID.LocalColorTableSize = 0;
  746.     ID.Reserved = 0;
  747.     ID.SortFlag = 0;
  748.     ID.InterlaceFlag = 0;
  749.     ID.LocalColorTableFlag = 0;
  750.     if (WriteImageDescriptor(&ID) != GIF_OK)
  751.         return GIF_ERRWRITE;
  752.     /*
  753.      *  Write code size
  754.      */
  755.     codesize = BitsNeeded(NumColors);
  756.     if (codesize == 1)
  757.         ++codesize;
  758.     if (WriteByte(codesize) != GIF_OK)
  759.         return GIF_ERRWRITE;
  760.     /*
  761.      *  Perform compression
  762.      */
  763.     RelPixX = RelPixY = 0;
  764.     GetPixel = getpixel;
  765.     imghandle = handle;
  766.     if ((errcode = LZW_Compress(codesize, InputByte)) != GIF_OK)
  767.         return errcode;
  768.     /*
  769.      *  Write terminating 0-byte
  770.      */
  771.     if (WriteByte(0) != GIF_OK)
  772.         return GIF_ERRWRITE;
  773.     return GIF_OK;
  774. }
  775. int GIF_Close(void)
  776. {
  777.     ImageDescriptor ID;
  778.     /*
  779.      *  Initiate and write ending image descriptor
  780.      */
  781.     ID.Separator = ';';
  782.     if (WriteImageDescriptor(&ID) != GIF_OK)
  783.         return GIF_ERRWRITE;
  784.     Close();
  785.     /*
  786.      *  Release color table
  787.      */
  788.     if (ColorTable) {
  789.         do_free(ColorTable);
  790.         ColorTable = NULL;
  791.     }
  792.     return GIF_OK;
  793. }