home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: Science / Science.zip / imdisp79.zip / IMAGEIO.C < prev    next >
C/C++ Source or Header  |  1993-09-03  |  41KB  |  1,168 lines

  1. /***  IMDISP module IMAGEIO.C
  2.      Image I/O routines for labeled images
  3.  
  4.      Includes routines for opening images, reading and writing
  5.      image lines, and converting pixel formats.
  6.  
  7.      Added GIF interface - Ron Baalke - 06/28/91
  8. ***/
  9.  
  10. #define __MSC
  11.  
  12. /* * * * INCLUDE files * * * */
  13.  
  14. #include <malloc.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <ctype.h>
  18. #include "mshell.h"
  19. #include "imdef.h"
  20. #include "imdisp.h"
  21. #include "imdutil.h"
  22. #include "fileio.h"
  23. #include "labutil.h"
  24. #include "palutil.h"
  25. #include "rescale.h"
  26. #include "gif_lib.h"
  27. #include "dispio.h"
  28. #include "mem.h"
  29. #include "textutil.h"
  30.  
  31. /* * * * External functions * * * */
  32. GifFileType *GifFileIn;
  33. GifFileType *GifFileOut;
  34. GifColorType *GifPalette;
  35. extern int _GifError;
  36.  
  37. /* * * * Function declarations * * * */
  38.  
  39. int ReadLabel (int, char *, int, char *);
  40. int WriteLabel (int, char *, unsigned int, char *);
  41. int OpenImage (char *, int, char *, int *, int *, int *, char *);
  42. int CloseImage (int, char *);
  43. int ReadLine (int, unsigned char *, int, int, int, char *);
  44. int WriteLine (int, unsigned char *, int, int, int, char *);
  45. int CheckStatus (char *);
  46. int ConvertLine (unsigned char *, unsigned char *, int, int, int, char *);
  47. int ReadXMSLine (unsigned char *, int, int, int);
  48. int OpenGifFile(char *, int *, int *, int *, char *);
  49. void gPrintGifError(char *buffer);
  50.  
  51. /* * * * Global Variables * * * */
  52.  
  53.               /* The image control block structure */
  54. struct ImageBlockType
  55.     {
  56.           long   block;        /* block # of start of buffer at */
  57.           int    blksiz;       /* block size in bytes */
  58.           int    maxbuf;       /* max size of buffer in blocks */
  59.           int    bufsiz;       /* # of blocks of buffer in use */
  60.  unsigned int    lblsiz;       /* label size in bytes */
  61.           int    pixsiz;       /* size of pixels in bits */
  62.           int    reclen;       /* record length in bytes */
  63.           int    nl, ns;       /* number of lines and samples */
  64.           int    linhed;       /* line header length in bytes */
  65.           char   access;       /* R for read, W for write */
  66.           int    gif;          /* GIF flag */
  67.     }   IMCB[MaxNumImages];
  68.  
  69.  
  70. unsigned char *ImageBuffer[MaxNumImages];    /* pointers to image buffers */
  71. int            ImageLocation;                /* where the image reside */
  72. int            ImageHandle;                  /* handle to extended mem */
  73. int            ImageMemory;
  74. int            ImageGifLine;
  75. char           LabelBuf[LabelBufferLen];
  76. char           LabelFileName[64];
  77. static unsigned char *gif_buffer;
  78.  
  79. int ReadLabel (int unit, char * LabelBuf, int LabelLength, char * status)
  80.  
  81. /* ReadLabel reads a buffer full of the beginning of the file and
  82.     copies part of it to the label buffer in uppercase.
  83. */
  84.  
  85. {
  86.     int   i, * len, length, next = 0;
  87.  
  88.     IMCB[unit].block = 0L;
  89.     ReadBlocks (unit, ImageBuffer[unit],  IMCB[unit].block,
  90.                   IMCB[unit].maxbuf, &IMCB[unit].bufsiz, status);
  91.     memcpy (LabelBuf, ImageBuffer[unit], LabelLength);
  92.     if (strncmp(LabelBuf+2,"CCSD",4) == 0 ||
  93.         strncmp(LabelBuf+2,"NJPL",4) == 0)
  94.     do
  95.     {
  96. /*       len = (int *)LabelBuf[next]; */
  97.        len = (int *) (LabelBuf + next);   /* len is a pointer to a 16-bit
  98.                                              integer - the record length     */
  99.        length = *len;                     /* and length is the number of
  100.                                              bytes in the label record       */
  101.        length += length%2;                /* word align the label record     */
  102. /*       LabelBuf[next] = 13; LabelBuf[next+1] = 10; */
  103.        *len = 0x0d0a;                     /* replace length w/ <CR><LF>      */
  104.        if (strncmp(LabelBuf+next+2,"END",3) == 0 && length < 5)
  105.            break;
  106.        next += length+2;                  /* bump next to next label record  */
  107.     }  while (next < LabelLength);
  108.  
  109.     for (i = 0;  i < LabelLength;  i++)
  110.         {
  111.          LabelBuf[i] = toupper(LabelBuf[i]);
  112.          if (LabelBuf[i] == 0) LabelBuf[i] = 32;
  113.         }
  114. }
  115.  
  116. int WriteLabel (int unit, char * LabelBuf, unsigned int labelsize,
  117.                 char * status)
  118.  
  119. /*  WriteLabel writes the passed label out to the image buffer.
  120.     If the label record is larger than the image buffer then
  121.     the buffer is written to disk.
  122. */
  123.  
  124. {
  125.     int   movebytes, bytesleft, inptr;
  126.  
  127.     strcpy (status, "");
  128.     memset (ImageBuffer[unit], 0, LabelBufferLen);
  129.  
  130.     IMCB[unit].block = 0L;
  131.     if (labelsize < LabelBufferLen)
  132.         movebytes = labelsize;
  133.     else
  134.         movebytes = LabelBufferLen;
  135.     memcpy (ImageBuffer[unit], LabelBuf, movebytes);
  136.     IMCB[unit].bufsiz = ((movebytes-1) / IMCB[unit].blksiz) + 1;
  137.     bytesleft = labelsize - movebytes;
  138.     inptr = movebytes;
  139.  
  140.     while (bytesleft > 0)
  141.     {
  142.         WriteBlocks (unit, ImageBuffer[unit], IMCB[unit].block,
  143.                        IMCB[unit].maxbuf, status);
  144.         if (strlen(status) > 0)  return(0);
  145.         IMCB[unit].block = IMCB[unit].block + IMCB[unit].maxbuf;
  146.         if (bytesleft < LabelBufferLen)
  147.             movebytes = bytesleft;
  148.         else
  149.             movebytes = LabelBufferLen;
  150.         memset (&ImageBuffer[unit][movebytes], 0, ImBufMax-movebytes);
  151.         memcpy (ImageBuffer[unit], &LabelBuf[inptr], movebytes);
  152.         IMCB[unit].bufsiz = ( (movebytes-1) / IMCB[unit].blksiz ) + 1;
  153.         bytesleft = bytesleft - movebytes;
  154.         inptr = inptr + movebytes;
  155.     }
  156. }
  157.  
  158. int OpenImage (char * filename, int unit, char * IOmode, int * p_nline,
  159.                int * p_nsamp, int * p_bitsperpix, char * status)
  160.  
  161. /***  OpenImage opens an image file either for reading or writing. The
  162.       size of the image and pixel format are returned if the file is
  163.       opened for reading.  If the file is opened for writing then the
  164.       passed number of lines and samples and pixel format are used for
  165.       the new image.  The unit number is used to refer to the file in
  166.       subsequent operations.  If the file is opened for input then the
  167.       label processing routines will parse Vicar2 and PDS labels and
  168.       will prompt for user info if the image is unlabeled. PDS detached
  169.       labels and palettes are handled transparently in this routine. If
  170.       the file is for writing then a PDS label will be output. An error
  171.       is returned if there is insufficient room to dynamically allocate
  172.       the image buffer, or if there is a file error. For images with
  173.       pixel sizes less than a byte, each line is assumed to start with a
  174.       new byte.
  175.  
  176.    Parameter    Type    In/out  Description
  177.  
  178.     filename  char ptr   in     Name of image file to open
  179.     unit        int      in     Unit number of image (0,1,2...)
  180.     IOmode    char ptr   in     Access mode of file
  181.                                   ("r..." for reading, "w..." for writing)
  182.     p_nline   int ptr  in/out   The number of lines in the image
  183.     p_nsamp   int ptr  in/out   The number of samples in the image
  184.  p_bitsperpix int ptr  in/out   The number of bits in a pixel (pixel format)
  185.                                   (16 for integer, 8 for byte,
  186.                                     4 for nibble,  1 for binary)
  187.     status    char ptr  out     Return string with error message
  188.                                   (0 length string if no error)
  189.  
  190. ***/
  191.  
  192. {
  193.     int     reclen, lineheadbytes, p;
  194. /*    unsigned int labelsize; */
  195.     unsigned int size;
  196.     char   accessmode[2], format, tmpstr[64];
  197.     char DetachedFileName[64];
  198.     char DetachedPaletteName[64];
  199.  
  200.     unsigned char *buffer;
  201.     int    i,j,k;
  202.     char   stat[128];
  203.     long   offset;
  204.     int    type;
  205.     unsigned long lsize;
  206.     int    error;
  207.     int    InterlacedOffset[4]; /* The way Interlaced image should  */
  208.     int    InterlacedJumps[4];  /* be read - offsets and jumps... */
  209.  
  210.     strcpy(status,"");
  211.  
  212.     InterlacedOffset[0] = 0;
  213.     InterlacedOffset[1] = 4;
  214.     InterlacedOffset[2] = 2;
  215.     InterlacedOffset[3] = 1;
  216.  
  217.     InterlacedJumps[0]  = 8;
  218.     InterlacedJumps[1]  = 8;
  219.     InterlacedJumps[2]  = 4;
  220.     InterlacedJumps[3]  = 2;
  221.  
  222.  
  223.     if ( (unit < 0) || (unit > MaxNumImages-1) )
  224.     {
  225.         strcpy (status, "Illegal unit number");
  226.         return(1);
  227.     }
  228.     accessmode[1] = 0;
  229.     accessmode[0] = toupper(IOmode[0]);
  230.     if (accessmode[0] != 'W')
  231.         accessmode[0] = 'R';
  232.  
  233.     if (strstr( filename, ".GIF") != NULL)      /* check for GIF file */
  234.        IMCB[unit].gif = TRUE;
  235.     else
  236.        IMCB[unit].gif = FALSE;
  237.     if (ImageFormat == GIF_FORMAT) IMCB[unit].gif = TRUE;
  238.  
  239.      if (IMCB[unit].gif)                       /* Open GIF file processing */
  240.      {
  241.        _GifError = 0;
  242.        if (accessmode[0] == 'R')
  243.        {
  244.           /* Open GIF for read */
  245.           error = OpenGifFile(filename,p_nline, p_nsamp, p_bitsperpix, status);
  246.           if (error != 0)
  247.              return(1);
  248.           labelsize = 0;
  249.           reclen = 0;
  250.           lineheadbytes = 0;
  251.  
  252.        }
  253.        else            /* else open GIF file for writing */
  254.        {
  255.           remove(filename);
  256.           EGifSetGifVersion("87a");
  257.           if (error == GIF_ERROR)
  258.           {
  259. /*             sprintf(status, "Error %d in EGifSetGifVersion", _GifError); */
  260.              gPrintGifError(status);
  261.              return(error);
  262.           }
  263.           GifFileOut = EGifOpenFileName( filename, TRUE);
  264.           if (GifFileOut == NULL)
  265.           {
  266. /*             sprintf(status,"Error %d in opening GIF file",_GifError); */
  267.              gPrintGifError(status);
  268.              return(1);
  269.           }
  270.           ReadPalette(CT);
  271.           GifPalette = (GifColorType *) CT;
  272.           error = EGifPutScreenDesc( GifFileOut, *p_nsamp, *p_nline, numDN, 0,
  273.                              *p_bitsperpix, GifPalette);
  274.           if (error == GIF_ERROR)
  275.           {
  276. /*             sprintf(status, "Error %d in EGifPutScreenDesc", _GifError); */
  277.              gPrintGifError(status);
  278.              return(error);
  279.           }
  280.           error = EGifPutImageDesc( GifFileOut, 0, 0, *p_nsamp, *p_nline, 0,
  281.                              *p_bitsperpix, NULL);
  282.           if (error == GIF_ERROR)
  283.           {
  284. /*             sprintf(status, "Error %d in EGifPutImageDesc", _GifError); */
  285.              gPrintGifError(status);
  286.              return(error);
  287.           }
  288.        }
  289.      }
  290.      else              /* else file is not GIF */
  291.      {
  292.        OpenFile (filename, unit, accessmode, &IMCB[unit].blksiz, status);
  293.        if (strlen(status) > 0) return(0);
  294.  
  295.        /* Allocate image buffer on heap */
  296.        /* Only allocate 2048 bytes for output buffer */
  297.        size = (accessmode[0]=='W') ? LabelBufferLen : ImBufMax;
  298.  
  299.        if ( (ImageBuffer[unit] = malloc (size)) == NULL )
  300.        {
  301.            free( ImageBuffer[unit] );
  302.            FatalError( "Not enough memory for ImageBuffer.\n");
  303.        }
  304.  
  305.  
  306.        IMCB[unit].maxbuf = size / IMCB[unit].blksiz; /* MDM 2/3/88*/
  307.  
  308.        if (accessmode[0] == 'R')
  309.        {
  310.            ReadLabel (unit, LabelBuf, LabelBufferLen, status);
  311.            if (strlen(status) > 0)  goto CloseUp;
  312.  
  313.    /*  patch for microsoft driver */
  314.    /*  this checks for dates found in certain positions in the extended
  315.        attr record. These could be found elsewhere, but probably not */
  316.            if (LabelBuf[10] == '1' && LabelBuf[11] == '9' &&
  317.                LabelBuf[26] == '1' && LabelBuf[27] == '9')
  318.              {
  319.                Microsoft = 1; /*read the label again*/
  320.                ReadLabel (unit, LabelBuf, LabelBufferLen, status);
  321.                if (strlen(status) > 0)  goto CloseUp;
  322.              }
  323.            else Microsoft = 0;
  324.  
  325. /*  end of patch */
  326.  
  327.            InterpretLabel (LabelBuf, LabelBufferLen,
  328.                            &labelsize, p_nline, p_nsamp, p_bitsperpix,
  329.                            &reclen, &lineheadbytes,  DetachedFileName,
  330.                            DetachedPaletteName, unit);
  331.            if (reclen == 0) return(0);
  332.            LabelFileName[0]=0;
  333.            if (strlen(DetachedFileName) > 0)
  334.            {
  335.                strcpy(LabelFileName,filename);
  336.                CloseFile (unit, status);
  337.                if ( (strchr(DetachedFileName, '\\') == NULL) &&
  338.                     (strchr(DetachedFileName, ':')  == NULL) &&
  339.                     (strnicmp(filename,"CD:",3)     != 0)  )
  340.                {
  341.                    p = strlen(filename) - 1;
  342.                    while ((p > -1) && (filename[p] != '\\')
  343.                                    && (filename[p] != ':')) p--;
  344.                    strcpy (tmpstr, filename);
  345.                    tmpstr[p+1] = 0;
  346.                    strcat (tmpstr, DetachedFileName);
  347.                    strcpy (DetachedFileName, tmpstr);
  348.                }
  349.  
  350.                OpenFile (DetachedFileName, unit, accessmode,
  351.                                          &IMCB[unit].blksiz, status);
  352.                if (strlen(status) > 0)  goto FreeUp;
  353.                IMCB[unit].maxbuf = ImBufMax / IMCB[unit].blksiz;
  354.                IMCB[unit].block = 0L;
  355.                ReadBlocks (unit, ImageBuffer[unit],  IMCB[unit].block,
  356.                      IMCB[unit].maxbuf, &IMCB[unit].bufsiz, status);
  357.                if (strlen(status) > 0)  goto CloseUp;
  358.  
  359.    /*  patch for microsoft driver */
  360.            if (ImageBuffer[unit][10] == '1' && ImageBuffer[unit][11] == '9' &&
  361.                ImageBuffer[unit][26] == '1' && ImageBuffer[unit][27] == '9')
  362.              {
  363.                Microsoft = 1; /*read the label again*/
  364.                ReadBlocks (unit, ImageBuffer[unit],  IMCB[unit].block,
  365.                      IMCB[unit].maxbuf, &IMCB[unit].bufsiz, status);
  366.                if (strlen(status) > 0)  goto CloseUp;
  367.              }
  368.            else Microsoft = 0;
  369.  
  370.            }
  371.  
  372.            if ( (strlen(DetachedPaletteName) > 0) || (Palette > 0L) )
  373.                                               /* Ron Baalke - Added detached */
  374.            {                                  /* palette processing - 07/27/90*/
  375.                LoadPalette(DetachedPaletteName);
  376.            }
  377.  
  378.        }
  379.  
  380.        else
  381.        {
  382.            reclen = ( (long)*p_nsamp* (long)*p_bitsperpix - 1 )/8 + 1;
  383.            if (ImageFormat != RAW_FORMAT)
  384.            {
  385.               MakeLabel (LabelBuf, &labelsize, *p_nline, *p_nsamp,
  386.                                                *p_bitsperpix, reclen);
  387.               WriteLabel (unit, LabelBuf, labelsize, status);
  388.               if (strlen(status) > 0)  goto CloseUp;
  389.            }
  390.            else
  391.               labelsize = 0;
  392.  
  393.            lineheadbytes = 0;
  394.        }
  395.     }
  396.     IMCB[unit].lblsiz = labelsize;
  397.     IMCB[unit].reclen = reclen;
  398.     IMCB[unit].nl = *p_nline;
  399.     IMCB[unit].ns = *p_nsamp;
  400.     IMCB[unit].pixsiz = *p_bitsperpix;
  401.     IMCB[unit].linhed = lineheadbytes;
  402.     IMCB[unit].access = accessmode[0];
  403.  
  404.     if (unit == 0)
  405.        ImageLocation = VIRTUAL_FILE;      /* Extended memory interface added*/
  406.                                            /* 05/18/91 - Ron Baalke */
  407.     if ((unit == 0) && (*p_bitsperpix == 8) &&
  408.         (accessmode[0] == 'R') && ImageMemory)
  409.     {
  410.        lsize = (long)(*p_nsamp) * (long)(*p_nline);
  411.        if (Memory_Alloc(lsize,&ImageHandle,&type) == 0)
  412.        {
  413.           size = *p_nsamp;
  414.           if ((buffer = malloc(size)) == NULL)
  415.               Memory_Free(ImageHandle, type);
  416.           else
  417.           {
  418.              if (PromptFlag)
  419.              {
  420.                if (IMCB[unit].gif)
  421.                   StatusLine(2, "Loading GIF into memory, please wait...");
  422.                 else
  423.                    StatusLine(2, "Loading image into memory, please wait....");
  424.              }
  425.  
  426.              strcpy(stat,"");
  427.  
  428.              /* special handle interlaced GIF's */
  429.  
  430.              if (IMCB[unit].gif && GifFileIn->IInterlace)
  431.              {
  432.                 size = *p_nsamp;
  433.                 for (i=0; i<4; i++)
  434.                    for (j=InterlacedOffset[i]; j<*p_nline;
  435.                         j += InterlacedJumps[i])
  436.                    {
  437.                       if (DGifGetLine(GifFileIn, buffer, size) == GIF_ERROR)
  438.                       {
  439. /*                         sprintf(status,"Error %d in reading interlaced GIF",_GifError); */
  440.                          gPrintGifError(status);
  441.                          Memory_Free(ImageHandle, type);
  442.                          DGifCloseFile( GifFileIn );
  443.                          if (gif_buffer != NULL) free(gif_buffer);
  444.                          free(buffer);
  445.                          return(1);
  446.                       }
  447.                       offset = (long)(j) * size;
  448.                       Memory_PutLine(ImageHandle, type, buffer, offset, size);
  449.                       k++;
  450.                    }
  451.              }
  452.              else  /* else read in image line by line */
  453.              {
  454.                 for (i=1; (i<=*p_nline) && (strlen(stat) == 0); i++)
  455.                 {
  456.                    ReadLine(0,buffer,i,1,size,stat);
  457.                    offset = (long)(i-1) * size;
  458.                    Memory_PutLine(ImageHandle, type, buffer, offset, size);
  459.                 }
  460.              }
  461.              if (strlen(stat) == 0)
  462.                 ImageLocation = type;
  463.              else
  464.              {
  465. /*                sprintf(status,"Error %d in reading line %d",_GifError,i-1); */
  466.                 gPrintGifError(status);
  467.                 DGifCloseFile( GifFileIn );
  468.                 Memory_Free(ImageHandle, type);
  469.                 if (gif_buffer != NULL) free(gif_buffer);
  470.                 free(buffer);
  471.                 return(1);
  472.              }
  473.  
  474.              free(buffer);
  475.           }
  476.        }
  477.     }
  478.  
  479.     /* Interlaced GIF's have to be in memory */
  480.  
  481.     if ((IMCB[unit].gif) && (GifFileIn->IInterlace) &&
  482.         (ImageLocation == VIRTUAL_FILE) && (accessmode[0] == 'R'))
  483.     {
  484.              strcpy(status,"Not enough memory for interlaced GIF");
  485.              DGifCloseFile( GifFileIn );
  486.              if (gif_buffer != NULL) free(gif_buffer);
  487.              return(1);
  488.     }
  489.  
  490.     return(0);
  491.  
  492.     CloseUp:
  493.       CloseFile (unit, LabelBuf);
  494.     FreeUp:
  495.       free(ImageBuffer[unit]);
  496. }
  497.  
  498. int ReadLine (int unit, unsigned char * buffer, int line, int sss, int nss,
  499.               char * status)
  500.  
  501. /***  ReadLine reads a line of pixels from the image into the user's
  502.       buffer.  The reading is completely random access, the lines may be
  503.       read in any order; it is more efficient, however, to read lines
  504.       sequentially.  Partial image lines may be read.  The output data
  505.       is in the same format as the file (the convert routine may be used
  506.       to convert pixel formats).
  507.  
  508.    Parameter Type   In/out  Description
  509.  
  510.     unit     int      in     Unit number of image (same as in open)
  511.     buffer  char ptr  out    Buffer to receive pixels
  512.     line     int      in     The number of the image line to read (1 is first)
  513.     sss      int      in     The starting sample in the line
  514.     nss      int      in     The number of samples to read into buffer
  515.     status  char ptr  out    Return string with error message
  516.                                   (0 length string if no error)
  517.  
  518. ***/
  519. {
  520.  
  521.     long      filebyte, blknum;
  522.     int       offset, bufsizebytes, numbytes;
  523.     int       movebytes, bytesleft, outptr;
  524.     unsigned char    hold, hold1;
  525.     int       i,j;
  526.     int       dummy1, dummy2, dummy3;
  527.  
  528.     strcpy (status, "");
  529.  
  530.     if (IMCB[unit].gif)   /* Process GIF files */
  531.     {
  532.        j = ImageGifLine;
  533.        if (line <= ImageGifLine) /* If past line, reset to beginning of file*/
  534.        {
  535.           if (DGifCloseFile(GifFileIn) == GIF_ERROR)
  536.           {
  537. /*             strcpy(status,"Error in closing GIF file"); */
  538.              gPrintGifError(status);
  539.              return(1);
  540.           }
  541.           if (gif_buffer != NULL) free(gif_buffer);
  542.           OpenGifFile(ImageFileName,&dummy1, &dummy2, &dummy3, status);
  543.           if (strlen(status) > 0)
  544.              return(1);
  545.           j = 0;
  546.        }
  547.        for (i=j; i<line; i++)  /* Now, get the line we want */
  548.        {
  549.           if (DGifGetLine(GifFileIn, gif_buffer, IMCB[0].ns) == GIF_ERROR)
  550.           {
  551. /*             sprintf(status,"Error %d in reading GIF line %d",_GifError,line); */
  552.              gPrintGifError(status);
  553.              return(1);
  554.           }
  555.        }
  556.        ImageGifLine = line;
  557. /*       memmove(buffer, gif_buffer+sss-1, nss); */
  558.        memcpy(buffer, gif_buffer+sss-1, nss);
  559.        return(0);
  560.     }
  561.     else  /* else process non-GIF file */
  562.     {
  563.         if (line > IMCB[unit].nl)
  564.            strcpy (status, "Line off image");
  565.    /* Calculate the block in the image to start at,
  566.                     and read it in if necessary */
  567.        filebyte = IMCB[unit].lblsiz
  568.                    + (long)(line-1) * (long)IMCB[unit].reclen
  569.                    + ( (long)(sss-1) * (long)IMCB[unit].pixsiz) / 8
  570.                    + (long)IMCB[unit].linhed;
  571.         if (GiantLabel > 0)
  572.         filebyte = GiantLabel
  573.                    + (long)(line-1) * (long)IMCB[unit].reclen
  574.                    + ( (long)(sss-1) * (long)IMCB[unit].pixsiz) / 8
  575.                    + (long)IMCB[unit].linhed;
  576.  
  577.         blknum = filebyte/IMCB[unit].blksiz;
  578.  
  579.        if ( (blknum < IMCB[unit].block) ||
  580.              (blknum > IMCB[unit].block + IMCB[unit].bufsiz-1)  )
  581.         {
  582.             IMCB[unit].block = blknum;
  583.             ReadBlocks (unit, ImageBuffer[unit], IMCB[unit].block,
  584.                  IMCB[unit].maxbuf, &IMCB[unit].bufsiz, status);
  585.             if (strlen(status) > 0)  return(0);
  586.         }
  587.  
  588.  
  589.         offset =  filebyte - IMCB[unit].blksiz*IMCB[unit].block;
  590.         numbytes = ( (long)nss*IMCB[unit].pixsiz - 1 ) /8 + 1;
  591.  
  592.    /* Transfer the part of the line thats in the image buffer */
  593.         bufsizebytes = IMCB[unit].blksiz*IMCB[unit].bufsiz;
  594.         movebytes = bufsizebytes - offset;
  595.         if (movebytes > numbytes)  movebytes = numbytes;
  596.         if (IMCB[unit].pixsiz == 16 && ByteSwap == TRUE)
  597.           swab(&ImageBuffer[unit][offset], buffer, movebytes);
  598.         else
  599.           memcpy (buffer, &ImageBuffer[unit][offset], movebytes);
  600.         bytesleft = numbytes - movebytes;
  601.         outptr = movebytes;
  602.  
  603.    /* Read in more buffer fulls and transfer until done */
  604.         while (bytesleft > 0)
  605.         {
  606.             IMCB[unit].block = IMCB[unit].block + IMCB[unit].bufsiz;
  607.             ReadBlocks (unit, ImageBuffer[unit], IMCB[unit].block,
  608.                           IMCB[unit].maxbuf, &IMCB[unit].bufsiz, status);
  609.             if (strlen(status) > 0) return(0);
  610.             bufsizebytes = IMCB[unit].blksiz*IMCB[unit].bufsiz;
  611.             if (bufsizebytes > bytesleft)  movebytes = bytesleft;
  612.                 else movebytes = bufsizebytes;
  613.             if (IMCB[unit].pixsiz == 16 && ByteSwap == TRUE)
  614.               swab(ImageBuffer[unit], &buffer[outptr], movebytes);
  615.             else
  616.               memcpy(&buffer[outptr], ImageBuffer[unit], movebytes);
  617.             bytesleft = bytesleft - movebytes;
  618.             outptr = outptr + movebytes;
  619.         }
  620.      /* swap bytes if FITS or other non swapped format */
  621. /*
  622.      if (IMCB[unit].pixsiz == 16  && ByteSwap == TRUE)
  623.        {
  624.          for (i=0;i<2*nss;i += 2)
  625.            {
  626.              hold = buffer[i+1];
  627.              buffer[i+1] = buffer[i];
  628.              buffer[i] = hold;
  629.            }
  630.        }
  631. */
  632.  
  633.      /* swap bytes for the 32 bits values. added by AEE, 4-4-89 */
  634.  
  635.      if ((IMCB[unit].pixsiz == 32) && ByteSwap == FALSE)
  636.        {
  637.         for (i=0; i <4*nss; i +=4)
  638.           {
  639.             hold= buffer[i+3];
  640.             hold1= buffer[i+2];
  641.             buffer[i+2]= buffer[i+1];
  642.             buffer[i+3]= buffer[i];
  643.             buffer[i]= hold;
  644.             buffer[i+1]= hold1;
  645.           }
  646.        }
  647.  
  648.  
  649.     }
  650. }
  651.  
  652. int WriteLine (int unit, unsigned char * buffer, int line, int sss, int nss,
  653.                char * status)
  654.  
  655. /***  WriteLine writes a line of pixels from the user buffer to the
  656.       image. Although the writing is buffered, completely random access
  657.       will not work; the image lines should be written sequentially.
  658.       Partial image lines may be written.  The input data must be in the
  659.       same format as the file (no conversion is performed).
  660.  
  661.    Parameter Type   In/out  Description
  662.  
  663.     unit     int      in     Unit number of image (same as in open)
  664.     buffer  char ptr  in     Buffer of image pixels
  665.     line     int      in     The number of the image line to write
  666.     sss      int      in     The starting sample in the line
  667.     nss      int      in     The number of samples to write from buffer
  668.     status  char ptr  out    Return string with error message
  669.                                   (0 length string if no error)
  670.  
  671. ***/
  672.  
  673. {
  674.     long      filebyte, blknum;
  675.     int       offset, bufsizebytes, numbytes;
  676.     int       movebytes, bytesleft, inptr;
  677.     int       gif_stat;
  678.  
  679.     if (IMCB[unit].gif)  /* Write out GIF line */
  680.     {
  681.        gif_stat = EGifPutLine( GifFileOut, buffer, nss);
  682.        if (gif_stat != GIF_OK)
  683.        {
  684.            sprintf (status, "Error writing GIF line %d", nss);
  685.            return(0);
  686.        }
  687.     }
  688.     else                /* else process non-GIF file */
  689.     {
  690.        if (line > IMCB[unit].nl)
  691.            strcpy (status, "Line off image");
  692.        else
  693.        {
  694.            strcpy (status, "");
  695.         /* Calculate the block in the image to start at */
  696.            filebyte = IMCB[unit].lblsiz
  697.                       + (line-1) * (long)IMCB[unit].reclen
  698.                       + ((sss-1) * (long)IMCB[unit].pixsiz) / 8
  699.                       + IMCB[unit].linhed;
  700.            blknum = filebyte/IMCB[unit].blksiz;
  701.            if ( (blknum < IMCB[unit].block) ||
  702.                 (blknum > IMCB[unit].block + IMCB[unit].bufsiz-1)  )
  703.            {
  704.                WriteBlocks (unit, ImageBuffer[unit], IMCB[unit].block,
  705.                              IMCB[unit].maxbuf,  status);
  706.                if (strlen(status) > 0)  return(0);
  707.                IMCB[unit].block = blknum;
  708.                memset (ImageBuffer[unit], 0, LabelBufferLen);
  709.            }
  710.  
  711.  
  712.            offset =  filebyte - IMCB[unit].blksiz*IMCB[unit].block;
  713.            numbytes = ( (long)nss*IMCB[unit].pixsiz - 1 ) /8 + 1;
  714.  
  715.  
  716.       /* Transfer the part of the line that fits in the image buffer */
  717.            bufsizebytes = LabelBufferLen;
  718.            movebytes = bufsizebytes - offset;
  719.            if (movebytes > numbytes)  movebytes = numbytes;
  720.            memcpy (&ImageBuffer[unit][offset], buffer, movebytes);
  721.            IMCB[unit].bufsiz = ((offset+movebytes-1) /IMCB[unit].blksiz) + 1;
  722.            bytesleft = numbytes - movebytes;
  723.            inptr = movebytes;
  724.  
  725.  
  726.       /* Write out more buffer fulls and transfer until done */
  727.            while (bytesleft > 0)
  728.            {
  729.                WriteBlocks (unit, ImageBuffer[unit], IMCB[unit].block,
  730.                               IMCB[unit].maxbuf, status);
  731.                if (strlen(status) > 0)  return(0);
  732.                IMCB[unit].block = IMCB[unit].block + IMCB[unit].maxbuf;
  733.                if (bufsizebytes > bytesleft)  movebytes = bytesleft;
  734.                  else movebytes = bufsizebytes;
  735.                memset (&ImageBuffer[unit][movebytes], 0, bufsizebytes-movebytes);
  736.                memcpy (ImageBuffer[unit], &buffer[inptr], movebytes);
  737.                IMCB[unit].bufsiz = ( (movebytes-1) /IMCB[unit].blksiz ) + 1;
  738.                bytesleft = bytesleft - movebytes;
  739.                inptr = inptr + movebytes;
  740.            }
  741.  
  742.        }
  743.     }
  744. }
  745.  
  746. int CloseImage (int unit, char * status)
  747.  
  748. /***  CloseImage closes the image file.  If the image is opened for
  749.     writing then the image buffer is first flushed.
  750.  
  751.    Parameter Type   In/out  Description
  752.  
  753.     unit     int      in     Unit number of image (same as in open)
  754.     status  char ptr  out    Return string with error message
  755.                                   (0 length string if no error)
  756. ***/
  757.  
  758. {
  759.     if (IMCB[unit].gif)
  760.     {
  761.        if (IMCB[unit].access == 'W')
  762.           EGifCloseFile( GifFileOut );
  763.        else
  764.        {
  765.           DGifCloseFile( GifFileIn );
  766.           if (gif_buffer != NULL) free(gif_buffer);
  767.        }
  768.     }
  769.     else
  770.     {
  771.  
  772.        if (IMCB[unit].access == 'W')
  773.        {
  774.            WriteBlocks (unit, ImageBuffer[unit], IMCB[unit].block,
  775.                                 IMCB[unit].bufsiz, status);
  776.            if (strlen(status) > 0) return(0);
  777.        }
  778.        free (ImageBuffer[unit]);
  779.        CloseFile (unit, status);
  780.     }
  781.  
  782.     if ((unit == 0) && (ImageLocation != VIRTUAL_FILE))
  783.        Memory_Free(ImageHandle, ImageLocation);
  784. }
  785.  
  786. int CheckStatus (char * status)
  787.  
  788. /***  CheckStatus checks the status string passed in.  If there is no
  789.       error the routine returns, otherwise the error message is printed
  790.       to the terminal and the program is aborted.
  791.  
  792. ***/
  793.  
  794. {
  795.     if (strlen(status) > 0)
  796.     {
  797.         printf ("%s\n", status);
  798.         abort();
  799.     }
  800. }
  801.  
  802. int ConvertLine (unsigned char * inbuffer, unsigned char * outbuffer,
  803.                  int inbits, int outbits, int ns, char * status)
  804.  
  805. /***  ConvertLine converts a line of pixels into a different format.
  806.  
  807.    Parameter     Type   In/out  Description
  808.  
  809.     inbuffer   char ptr  in    The input buffer of pixels
  810.     outbuffer  char ptr  out   The output buffer of pixels
  811.     inbits      int      in    The pixel format of the input buffer
  812.     outbits     int      in    The pixel format of the output buffer
  813.     ns          int      in    The number of samples to convert
  814.     status     char ptr  out   Return string with error message
  815.  
  816.  
  817.    Conversions supported :        outbits
  818.                                 1  4  8  16 32
  819.                    inbits    1  .  -  .  .  -    . means supported
  820.                              4  -  .  .  .  -    - means not supported
  821.                              8  .  .  .  .  .
  822.                             16  .  .  .  .  .
  823.                             32  -  -  .  .  .
  824. ***/
  825.  
  826. {
  827.  
  828.     register  i, j;
  829.     int       bit;
  830.  
  831.     union {
  832.           unsigned char   *b;
  833.           int             *i;
  834.           long            *l;
  835.           } inbuf, outbuf;
  836.     inbuf.b = inbuffer;
  837.     outbuf.b = outbuffer;
  838.  
  839.  
  840.  
  841.     strcpy (status, "");
  842.     i = 0;   j = 0;
  843.  
  844.     if (inbits == outbits)
  845.         memcpy (outbuffer, inbuffer, (size_t)( (long)ns*inbits - 1 )/8 + 1 );
  846.  
  847.     else if ( (inbits==8) && (outbits==16) )
  848.        b2w( inbuf.b, outbuf.i, ns);
  849.  
  850.     else if ( (inbits==16) && (outbits==8) )
  851.        w2b( inbuf.i, outbuf.b, ns);
  852.  
  853.     else if ( (inbits==16) && (outbits==32) )
  854.         for (i = 0; i < ns; i++)
  855.             outbuf.l[i] = inbuf.i[i];
  856.  
  857.     else if ( (inbits==32) && (outbits==16) )
  858.         for (i = 0; i < ns; i++)
  859.             outbuf.i[i] = inbuf.l[i];
  860.  
  861.     else if ( (inbits==8) && (outbits==32) )
  862.         for (i = 0; i < ns; i++)
  863.             outbuf.l[i] = inbuf.b[i];
  864.  
  865.     else if ( (inbits==32) && (outbits==8) )
  866.         for (i = 0; i < ns; i++)
  867.             outbuf.b[i] = inbuf.l[i];
  868.  
  869.     else if ( (inbits==4) && (outbits==8) )
  870.         for (i = 0; i <= (ns-1)/2; i++)
  871.         {   outbuf.b[j++] = inbuf.b[i] >> 4;
  872.             outbuf.b[j++] = inbuf.b[i] & 15;
  873.         }
  874.  
  875.     else if ( (inbits==8) && (outbits==4) )
  876.         for (j = 0; j <= (ns-1)/2; j++)
  877.         {
  878.             outbuf.b[j] = (inbuf.b[i++] << 4) | (inbuf.b[i++] & 15);
  879.         }
  880.  
  881.     else if ( (inbits==1) && (outbits==8) )
  882.         for (i = 0; i <= (ns-1)/8; i++)
  883.             for (bit = 7; bit >= 0; bit--)
  884.                 outbuf.b[j++] = (inbuf.b[i] >> bit) & 1;
  885.  
  886.     else if ( (inbits==8) && (outbits==1) )
  887.         for (j = 0; j <= (ns-1)/8; j++)
  888.         {   outbuf.b[j] = 0;
  889.             for (bit = 7; bit >= 0; bit--)
  890.                 outbuf.b[j] |= ((inbuf.b[i++] & 1) << bit);
  891.         }
  892.  
  893.  
  894.     else if ( (inbits==4) && (outbits==16) )
  895.         for (i = 0; i <= (ns-1)/2; i++)
  896.         {   outbuf.i[j++] = inbuf.b[i] >> 4;
  897.             outbuf.i[j++] = inbuf.b[i] & 15;
  898.         }
  899.  
  900.     else if ( (inbits==16) && (outbits==4) )
  901.         for (j = 0; j <= (ns-1)/2; j++)
  902.             outbuf.b[j] = (inbuf.i[i++] << 4) | (inbuf.i[i++] & 15);
  903.  
  904.     else if ( (inbits==1) && (outbits==16) )
  905.         for (i = 0; i <= (ns-1)/8; i++)
  906.             for (bit = 7; bit >= 0; bit--)
  907.                 outbuf.i[j++] = (inbuf.b[i] >> bit) & 1;
  908.  
  909.     else if ( (inbits==16) && (outbits==1) )
  910.         for (j = 0; j <= (ns-1)/8; j++)
  911.         {   outbuf.b[j] = 0;
  912.             for (bit = 7; bit >= 0; bit--)
  913.                 outbuf.b[j] |= ((inbuf.i[i++] & 1) << bit);
  914.         }
  915.  
  916.     else
  917.         strcpy (status, "That pixel conversion is not supported");
  918. }
  919.  
  920. int ReadXMSLine(unsigned char * buffer, int line, int ss, int ns)
  921. /***  ReadsXMSLine reads a line of pixels of the image from extended memory
  922.       Parameter   type       description
  923.         buffer   char ptr    The receiving array of pixel values
  924.         line     integer     The line coordinate of the first pixel
  925.         ss       integer     The sample coordinate of the first pixel
  926.         ns       integer     The number of pixels to read
  927. ***/
  928. {
  929.     int    n_bytes;
  930.     long   offset;
  931.  
  932.     offset = (long)(line-1) * IMCB[0].ns + ss - 1;
  933.  
  934.     Memory_GetLine(ImageHandle, ImageLocation, buffer, offset, ns);
  935.     n_bytes = ns;
  936.  
  937.     return( n_bytes );
  938. }
  939.  
  940. /*************************************************************************/
  941. /* OpenGifFile                                                           */
  942. /*                                                                       */
  943. /* Written by Ron Baalke - 11/91                                         */
  944. /*                                                                       */
  945. /* This routine will open the GIF file, load in the color palette, and   */
  946. /* skip all the records until it is pointing the first line of data.     */
  947. /*                                                                       */
  948. /* It is written as a separate routine do avoid duplicate code, since    */
  949. /* the OpenImage() and ReadLine() routine needs to do the exact thing    */
  950. /* when it opens a GIF image.                                            */
  951. /*************************************************************************/
  952.  
  953. int OpenGifFile(char * filename, int * p_nline, int * p_nsamp,
  954.                          int * p_bitsperpix, char * status)
  955. {
  956.    int i;
  957.    int done;
  958.    GifRecordType RecordType;
  959.    GifByteType *Extension;
  960.    int    ExtCode;
  961.    GifColorType  *pcolor;
  962.    int    factor;
  963.    int    bitsperpix, nline, nsamp;
  964.  
  965.    strcpy(status,"");
  966.    ImageGifLine = 0;
  967.  
  968.    GifFileIn = DGifOpenFileName( filename);  /* Open GIF for read */
  969.    if (GifFileIn == NULL)
  970.    {
  971.       sprintf(status,"Error %d in opening GIF file",_GifError);
  972.       return(1);
  973.    }
  974.  
  975.    done = FALSE;
  976.    do {                       /* Get GIF record type */
  977.       if (DGifGetRecordType(GifFileIn, &RecordType) == GIF_ERROR)
  978.       {
  979. /*         sprintf(status,"Error %d in reading GIF record type",_GifError); */
  980.          gPrintGifError(status);
  981.          return(1);
  982.       }
  983.       switch (RecordType) {
  984.  
  985.          case IMAGE_DESC_RECORD_TYPE:
  986.             if (DGifGetImageDesc(GifFileIn) == GIF_ERROR)
  987.             {
  988. /*               sprintf(status,"Error %d in reading GIF image description",_GifError); */
  989.                gPrintGifError(status);
  990.                DGifCloseFile( GifFileIn );
  991.                if (gif_buffer != NULL) free(gif_buffer);
  992.                return(1);
  993.             }
  994.             nline      = GifFileIn->IHeight;
  995.             nsamp      = GifFileIn->IWidth;
  996.  
  997.             if ((gif_buffer = malloc (nsamp)) == NULL )
  998.             {
  999.                strcpy(status,"Not enough memory for GIF buffer");
  1000.                DGifCloseFile( GifFileIn );
  1001.                return(1);
  1002.             }
  1003.  
  1004.             if (GifFileIn->SColorMap != NULL)
  1005.             {
  1006.                bitsperpix = GifFileIn->SBitsPerPixel;
  1007.                pcolor = (GifColorType *)GifFileIn->SColorMap;
  1008.             }
  1009.             else if (GifFileIn->IColorMap != NULL)
  1010.             {
  1011.                bitsperpix = GifFileIn->IBitsPerPixel;
  1012.                 pcolor = (GifColorType *)GifFileIn->IColorMap;
  1013.             }
  1014.             else
  1015.             {
  1016.                strcpy(status,"Error in reading GIF color map");
  1017.                DGifCloseFile( GifFileIn );
  1018.                if (gif_buffer != NULL) free(gif_buffer);
  1019.                return(1);
  1020.             }
  1021.  
  1022.             if (bitsperpix > 8) bitsperpix = 8;
  1023.  
  1024.             /* Read in GIF color palette */
  1025.             for (i=0; i<256; i++)
  1026.             {
  1027.                CT[i].r = i;
  1028.                CT[i].g = i;
  1029.                CT[i].b = i;
  1030.             }
  1031.             factor = (1 << bitsperpix);
  1032.             for (i=0; i<factor; i++)
  1033.             {
  1034.                CT[i].r = pcolor[i].Red;
  1035.                CT[i].g = pcolor[i].Green;
  1036.                CT[i].b = pcolor[i].Blue;
  1037.             }
  1038.  
  1039.             *p_bitsperpix = 8;
  1040.             *p_nline = nline;
  1041.             *p_nsamp  = nsamp;
  1042.  
  1043.             WritePalette(CT);
  1044.             done = TRUE;
  1045.             break;
  1046.  
  1047.          case EXTENSION_RECORD_TYPE:
  1048.             /* Skip any extension blocks in file: */
  1049.             if (DGifGetExtension(GifFileIn, &ExtCode, &Extension)
  1050.                 == GIF_ERROR)
  1051.             {
  1052. /*               sprintf(status,"Error %d in reading GIF extension block",_GifError); */
  1053.                gPrintGifError(status);
  1054.                DGifCloseFile( GifFileIn );
  1055.                if (gif_buffer != NULL) free(gif_buffer);
  1056.                return(1);
  1057.             }
  1058.             while (Extension != NULL)
  1059.             {
  1060.                if (DGifGetExtensionNext(GifFileIn, &Extension)
  1061.                     == GIF_ERROR)
  1062.                {
  1063. /*                  sprintf(status,"Error %d in reading GIF extension block",_GifError); */
  1064.                   gPrintGifError(status);
  1065.                   DGifCloseFile( GifFileIn );
  1066.                   if (gif_buffer != NULL) free(gif_buffer);
  1067.                   return(1);
  1068.                }
  1069.             }
  1070.             break;
  1071.  
  1072.          default:
  1073.             done = TRUE;
  1074.             break;
  1075.          }
  1076.       }
  1077.    while (!done);
  1078.  
  1079.    return(0);
  1080. }
  1081.  
  1082. /*****************************************************************************
  1083. * Print the last GIF error to graphics screen                        *
  1084. *****************************************************************************/
  1085. void gPrintGifError(char *buffer)
  1086. {
  1087.     char *Err;
  1088.  
  1089.     switch(_GifError) {
  1090.     case E_GIF_ERR_OPEN_FAILED:
  1091.         Err = "Failed to open given file";
  1092.         break;
  1093.     case E_GIF_ERR_WRITE_FAILED:
  1094.         Err = "Failed to Write to given file";
  1095.         break;
  1096.     case E_GIF_ERR_HAS_SCRN_DSCR:
  1097.         Err = "Screen Descriptor already been set";
  1098.         break;
  1099.     case E_GIF_ERR_HAS_IMAG_DSCR:
  1100.         Err = "Image Descriptor is still active";
  1101.         break;
  1102.     case E_GIF_ERR_NO_COLOR_MAP:
  1103.         Err = "Neither Global Nor Local color map";
  1104.         break;
  1105.     case E_GIF_ERR_DATA_TOO_BIG:
  1106.         Err = "#Pixels bigger than Width * Height";
  1107.         break;
  1108.     case E_GIF_ERR_NOT_ENOUGH_MEM:
  1109.         Err = "Fail to allocate required memory";
  1110.         break;
  1111.     case E_GIF_ERR_DISK_IS_FULL:
  1112.         Err = "Write failed (disk full?)";
  1113.         break;
  1114.     case E_GIF_ERR_CLOSE_FAILED:
  1115.         Err = "Failed to close given file";
  1116.         break;
  1117.     case E_GIF_ERR_NOT_WRITEABLE:
  1118.         Err = "Given file was not opened for write";
  1119.         break;
  1120.     case D_GIF_ERR_OPEN_FAILED:
  1121.         Err = "Failed to open given file";
  1122.         break;
  1123.     case D_GIF_ERR_READ_FAILED:
  1124.         Err = "Failed to Read from given file";
  1125.         break;
  1126.     case D_GIF_ERR_NOT_GIF_FILE:
  1127.         Err = "Given file is NOT GIF file";
  1128.         break;
  1129.     case D_GIF_ERR_NO_SCRN_DSCR:
  1130.         Err = "No Screen Descriptor detected";
  1131.         break;
  1132.     case D_GIF_ERR_NO_IMAG_DSCR:
  1133.         Err = "No Image Descriptor detected";
  1134.         break;
  1135.     case D_GIF_ERR_NO_COLOR_MAP:
  1136.         Err = "Neither Global Nor Local color map";
  1137.         break;
  1138.     case D_GIF_ERR_WRONG_RECORD:
  1139.         Err = "Wrong record type detected";
  1140.         break;
  1141.     case D_GIF_ERR_DATA_TOO_BIG:
  1142.         Err = "#Pixels bigger than Width * Height";
  1143.         break;
  1144.     case D_GIF_ERR_NOT_ENOUGH_MEM:
  1145.         Err = "Fail to allocate required memory";
  1146.         break;
  1147.     case D_GIF_ERR_CLOSE_FAILED:
  1148.         Err = "Failed to close given file";
  1149.         break;
  1150.     case D_GIF_ERR_NOT_READABLE:
  1151.         Err = "Given file was not opened for read";
  1152.         break;
  1153.     case D_GIF_ERR_IMAGE_DEFECT:
  1154.         Err = "Image is defective, decoding aborted";
  1155.         break;
  1156.     case D_GIF_ERR_EOF_TOO_SOON:
  1157.         Err = "Image EOF detected, before image complete";
  1158.         break;
  1159.     default:
  1160.         Err = NULL;
  1161.         break;
  1162.     }
  1163.     if (Err != NULL)
  1164.     sprintf(buffer, "GIF-LIB error: %s.", Err);
  1165.     else
  1166.     sprintf(buffer, "GIF-LIB undefined error %d.", _GifError);
  1167. }
  1168.