IGIF.c
资源名称:ilib [点击查看]
上传用户:changbiao
上传日期:2007-01-13
资源大小:141k
文件大小:11k
源码类别:

图片显示

开发平台:

C/C++

  1. /*
  2.  * IGIF.c
  3.  *
  4.  * Image library
  5.  *
  6.  * Description:
  7.  * Portable routines to manipulate raster images.
  8.  *
  9.  * Previous version of Ilib used code from pbmplus to save GIF images.
  10.  * Due to copyright issues with encoding GIFs, the GIF encoding routines
  11.  * have been removed.  Instead we use Giflib which is freely available at:
  12.  * http://prtr-13.ucsc.edu/~badger/software/giflib.shtml
  13.  *
  14.  * Libungif is available at:
  15.  * http://prtr-13.ucsc.edu/~badger/software/libungif.shtml
  16.  *
  17.  * Note that you may use giflib or libungif.  They are basically the same
  18.  * library except that libungif does not include the questionable LZW
  19.  * compression algorithm (that's subject to the Unisys copyright.)  Thus,
  20.  * GIFs from libungif will be uncompressed (larger).
  21.  *
  22.  * Thanks to Eric S. Raymond and Gershon Elber for making Giflib available.
  23.  *
  24.  * History:
  25.  * 20-Aug-99 Craig Knudsen   cknudsen@radix.net
  26.  * Support writing transparent colors.
  27.  * 19-Aug-99 Craig Knudsen   cknudsen@radix.net
  28.  * Updated to support writing interlaced GIF files.
  29.  * Added support for reading/writing comments.
  30.  * Added support for reading transparent color.
  31.  * 18-Aug-99 Craig Knudsen   cknudsen@radix.net
  32.  * Updated to support GIF extensions (like interlace)
  33.  * when reading files.
  34.  * 17-May-98 Craig Knudsen cknudsen@radix.net
  35.  * Updated to use Giflib instead of doing or own
  36.  * GIF encoding.  Saves me from getting sued ;-)
  37.  * 20-May-96 Craig Knudsen cknudsen@radix.net
  38.  * Created
  39.  *
  40.  ****************************************************************************/
  41. #ifdef HAVE_GIFLIB
  42. #include <stdio.h>
  43. #include <stdlib.h>
  44. #include <ctype.h>
  45. #include <memory.h>
  46. #define PROGRAM_NAME "Ilib"
  47. #include <gif_lib.h>
  48. #include "Ilib.h"
  49. #include "IlibP.h"
  50. #define colors_match(color,r,g,b) 
  51.  (color->red == r && color->green == g && color->blue == b )
  52. #define MAX_COLORMAP_SIZE       (256)
  53. #define ABS(a) (a < 0 ? (0-a) : a )
  54. static int InterlacedOffset[] = { 0, 4, 2, 1 };
  55. static int InterlacedJumps[] = { 8, 8, 4, 2 };
  56. static int color_compare ( r, g, b, test1, test2 )
  57. unsigned int r, g, b;
  58. IColorP *test1, *test2;
  59. {
  60.   int diff1, diff2;
  61.   diff1 = ABS ( (int)r - (int)test1->red ) +
  62.     ABS ( (int)g - (int)test1->green ) +
  63.     ABS ( (int)b - (int)test1->blue );
  64.   diff2 = ABS ( (int)r - (int)test2->red ) +
  65.     ABS ( (int)g - (int)test2->green ) +
  66.     ABS ( (int)b - (int)test2->blue );
  67.   return ( diff1 > diff2 );
  68. }
  69. IError _IWriteGIF ( fp, image, options )
  70. FILE *fp;
  71. IImageP *image;
  72. IOptions options;
  73. {
  74.   int r, c, offset;
  75.   unsigned char *ptr;
  76.   unsigned int red, green, blue;
  77.   IColorP *colormap[MAX_COLORMAP_SIZE];
  78.   ColorMapObject *GIFcolormap;
  79.   int num_colors = 0, color_ceil, loop, loop2, closest, bits_per_pixel;
  80.   int color_found;
  81.   int transparent = -1, interlaced = 0;
  82.   int fd;
  83.   GifFileType *gft;
  84.   GifByteType ext[4];
  85.   unsigned char *data;
  86.   /* first make an 8-bit version of the image */
  87.   data = (unsigned char *) calloc ( image->width * image->height,
  88.     sizeof ( unsigned char ) );
  89.   memset ( data, '', sizeof ( image->width * image->height ) );
  90.   /* Reduce to 256 colors
  91.   ** This is a god-awful hack of an algorithm.  Should really use a
  92.   ** better one.
  93.   ** The first 256 colors found will be used, the rest will be converted
  94.   ** to closest.
  95.   ** NOTE: we should change this to call QuantizeBuffer in GIFLIB.
  96.   */
  97.   for ( r = 0; r < image->height; r++ ) {
  98.     for ( c = 0; c < image->width; c++ ) {
  99.       offset = ( r * image->width ) + c;
  100.       if ( image->greyscale ) {
  101.         ptr = image->data + ( r * image->width ) + c;
  102.         red = green = blue = (unsigned int) *ptr;
  103.       }
  104.       else {
  105.         ptr = image->data + ( r * image->width * 3 ) + ( c * 3 );
  106.         red = (unsigned int) *ptr;
  107.         green = (unsigned int) *( ptr + 1 );
  108.         blue = (unsigned int) *( ptr + 2 );
  109.       }
  110.       color_found = 0;
  111.       for ( loop = 0; loop < num_colors; loop++ ) {
  112.         if ( colors_match ( colormap[loop], red, green, blue ) ) {
  113.           data[offset] = loop;
  114.           color_found = 1;
  115.           break;
  116.         }
  117.       }
  118.       if ( ! color_found ) {
  119.         if ( num_colors < MAX_COLORMAP_SIZE ) {
  120.           colormap[num_colors] = (IColorP *) malloc ( sizeof ( IColorP ) );
  121.           memset ( colormap[num_colors], '', sizeof ( IColorP ) );
  122.           colormap[num_colors]->magic = IMAGIC_COLOR;
  123.           colormap[num_colors]->red = red;
  124.           colormap[num_colors]->green = green;
  125.           colormap[num_colors]->blue = blue;
  126.           data[offset] = num_colors;
  127.           num_colors++;
  128.         } else {
  129.           // find closest!
  130.           closest = 0;
  131.           for ( loop = 0; loop < num_colors; loop++ ) {
  132.             if ( color_compare ( red, green, blue, colormap[closest],
  133.               colormap[loop] ) < 0 )
  134.               closest = loop;
  135.           }
  136.         }
  137.       }
  138.     }
  139.   }
  140.   /* how many cells in colormap (eg. 28->32, 55->64, etc.) */
  141.   for ( bits_per_pixel = 1, color_ceil = 2; color_ceil < num_colors;
  142.     color_ceil *= 2, bits_per_pixel++ ) ;
  143.   fd = fileno ( fp );
  144.   GIFcolormap = MakeMapObject ( color_ceil, NULL );
  145.   for ( loop = 0; loop < color_ceil; loop++ ) {
  146.     if ( loop < num_colors ) {
  147.       GIFcolormap->Colors[loop].Red = colormap[loop]->red;
  148.       GIFcolormap->Colors[loop].Green = colormap[loop]->green;
  149.       GIFcolormap->Colors[loop].Blue = colormap[loop]->blue;
  150.     } else {
  151.       GIFcolormap->Colors[loop].Red = GIFcolormap->Colors[loop].Green =
  152.         GIFcolormap->Colors[loop].Blue = 0;
  153.     }
  154.   }
  155.   gft = EGifOpenFileHandle ( fileno ( fp ) );
  156.   /* causes seg fault...
  157.   EGifSetGifVersion ( "89a" );
  158.   */
  159.   if ( options & IOPTION_INTERLACED )
  160.     interlaced = 1;
  161.   if ( image->transparent ) {
  162.     for ( loop = 0; loop < num_colors; loop++ ) {
  163.       if ( colors_match ( colormap[loop], image->transparent->red,
  164.         image->transparent->green, image->transparent->blue ) ) {
  165.         transparent = loop;
  166.         break;
  167.       }
  168.     }
  169.   }
  170.   else
  171.     transparent = -1;
  172.   if ( EGifPutScreenDesc ( gft, image->width, image->height,
  173.     bits_per_pixel, 0, GIFcolormap ) == GIF_ERROR )
  174.     return ( IGIFError );
  175.   if ( image->comments )
  176.     EGifPutComment ( gft, image->comments );
  177.   if ( transparent >= 0 ) {
  178.     ext[0] = 1;
  179.     ext[1] = 0;
  180.     ext[2] = 0;
  181.     ext[3] = transparent;
  182.     EGifPutExtension ( gft, GRAPHICS_EXT_FUNC_CODE, 4, ext );
  183.   }
  184.   if ( EGifPutImageDesc ( gft, 0, 0, image->width, image->height,
  185.     interlaced, NULL ) == GIF_ERROR )
  186.     return ( IGIFError );
  187.   /* for interlaced images, we need to write the rows in a different order */
  188.   if ( interlaced ) {
  189.     for ( loop = 0; loop < 4; loop++ ) {
  190.       for ( loop2 = InterlacedOffset[loop]; loop2 < image->height;
  191.         loop2 += InterlacedJumps[loop] ) {
  192.         if ( EGifPutLine ( gft, data + ( loop2 * image->width ), image->width )
  193.           == GIF_ERROR )
  194.          return ( IGIFError );
  195.       }
  196.     }
  197.   } else {
  198.     /* Write the data all at once */
  199.     if ( EGifPutLine ( gft, data, image->width * image->height ) == GIF_ERROR )
  200.       return ( IGIFError );
  201.   }
  202.   EGifCloseFile ( gft );
  203.   /* free up allocated resources */
  204.   free ( data );
  205.   for ( loop = 0; loop < num_colors; loop++ ) {
  206.     free ( colormap[loop] );
  207.   }
  208.   FreeMapObject ( GIFcolormap );
  209.   return ( INoError );
  210. }
  211. IError _IReadGIF ( fp, options, image_return )
  212. FILE *fp;
  213. IOptions options;
  214. IImageP **image_return;
  215. {
  216.   IImageP *image = NULL;
  217.   GifFileType *gft;
  218.   GifRecordType rt;
  219.   GifPixelType *gifdata = NULL;
  220.   GifByteType *extension;
  221.   int extcode;
  222.   int fd;
  223.   int loop, loop2, col;
  224.   unsigned char *ptr, *r, *g, *b;
  225.   unsigned int temp;
  226.   char *comments = NULL;
  227.   unsigned int transparent_ind;
  228.   int trans_set = 0;
  229.   IColor transcolor;
  230.   fd = fileno ( fp );
  231.   if ( ( gft = DGifOpenFileHandle ( fd ) ) == NULL )
  232.     return ( IGIFError );
  233.   while ( image == NULL ) {
  234.     rt = UNDEFINED_RECORD_TYPE;
  235.     if ( DGifGetRecordType ( gft, &rt ) == GIF_ERROR )
  236.       return ( IGIFError );
  237.     if ( rt == IMAGE_DESC_RECORD_TYPE ) {
  238.       if ( DGifGetImageDesc ( gft ) == GIF_ERROR )
  239.         return ( IGIFError );
  240.       image = (IImageP *) ICreateImage ( gft->Image.Width,
  241.         gft->Image.Height, IOPTION_NONE );
  242.       gifdata = (GifPixelType *) malloc ( image->width  * image->height );
  243.       /* we read the lines out of order for interlaced images (yuck) */
  244.       if ( gft->Image.Interlace ) {
  245.         for ( loop = 0; loop < 4; loop++ ) {
  246.           for ( loop2 = InterlacedOffset[loop]; loop2 < image->height;
  247.             loop2 += InterlacedJumps[loop] ) {
  248.             if ( DGifGetLine ( gft, gifdata + ( loop2 * image->width ),
  249.               image->width ) == GIF_ERROR )
  250.               return ( IGIFError );
  251.           }
  252.         }
  253.       } else {
  254.         if ( DGifGetLine ( gft, gifdata, image->width * image->height )
  255.           == GIF_ERROR )
  256.           return ( IGIFError );
  257.       }
  258.       /* convert to a 24-bit image */
  259.       for ( loop = 0; loop < image->height; loop++ ) {
  260.         for ( col = 0; col < image->width; col++ ) {
  261.           ptr = gifdata + ( loop * image->width ) + col;
  262.           temp = *ptr;
  263.           r = image->data + ( loop * image->width * 3 ) + ( col * 3 );
  264.           g = r + 1;
  265.           b = r + 2;
  266.           if ( temp > gft->SColorMap->ColorCount ) {
  267.             temp = gft->SColorMap->ColorCount - 1;
  268.             fprintf ( stderr, "ILib Warning: Invalid color found in GIF.n" );
  269.           }
  270.           *r = gft->SColorMap->Colors[temp].Red;
  271.           *g = gft->SColorMap->Colors[temp].Green;
  272.           *b = gft->SColorMap->Colors[temp].Blue;
  273.         }
  274.       }
  275.     } else if ( rt == EXTENSION_RECORD_TYPE ) {
  276.       /* ignore all extensions except comments */
  277.       DGifGetExtension ( gft, &extcode, &extension );
  278.       while ( extension != NULL ) {
  279.         if ( extcode == COMMENT_EXT_FUNC_CODE ) {
  280.           if ( comments != NULL )
  281.             free ( comments );
  282.           comments = (char *) malloc ( strlen ( extension + 1 ) + 1 );
  283.           strcpy ( comments, extension + 1 );
  284.         } else if ( extcode == GRAPHICS_EXT_FUNC_CODE ) {
  285.           /* this is used to set transparent color index */
  286.           if ( extension[1] & 0x01 ) {
  287.             trans_set = 1;
  288.             transparent_ind = extension[4];
  289.           }
  290.         } else {
  291.           /*
  292.           fprintf ( stderr, "Ignoring unknown extension: %dn",
  293.             extension[0] );
  294.           */
  295.         }
  296.         DGifGetExtensionNext ( gft, &extension );
  297.       }
  298.     }
  299.   }
  300.   /* lookup transparent color from colormap */
  301.   if ( trans_set ) {
  302.     transcolor = IAllocColor (
  303.       gft->SColorMap->Colors[transparent_ind].Red,
  304.       gft->SColorMap->Colors[transparent_ind].Green,
  305.       gft->SColorMap->Colors[transparent_ind].Blue );
  306.     ISetTransparent ( image, transcolor );
  307.   }
  308.   image->comments = comments;
  309.   if ( gifdata )
  310.     free ( gifdata );
  311.   DGifCloseFile ( gft );
  312.   *image_return = image;
  313.   return ( INoError );
  314. }
  315. #endif /* HAVE_GIFLIB */