home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / mkanim.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  19.3 KB  |  768 lines

  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /**********************************************************************
  19.  mkanim.c
  20.  By Daniel Malmer
  21.  
  22.  This code was mostly taken from mkicons.c.
  23.  
  24.  Given a list of filenames, creates a datafile that is read in by the
  25.  browser at run-time.  The images in the datafile will be used as the
  26.  custom animation.
  27.  
  28.  Usage:
  29.  
  30.     mkanim large-file1 large-file2... large-filen small-file1 small-file2... 
  31.            small-filen
  32.  
  33. **********************************************************************/
  34.  
  35. /*
  36.    mkicons.c --- converting transparent GIFs to embeddable XImage data.
  37.    Created: Jamie Zawinski <jwz@netscape.com>, 17-Aug-95.
  38.    (Danger.  Here be monsters.)
  39.  */
  40.  
  41. #define MAX_ANIM_FRAMES 50
  42.  
  43. #ifdef sgi
  44. #include <bstring.h>
  45. #else
  46. #include <string.h>
  47. #endif
  48.  
  49. #ifdef _HPUX_SOURCE
  50. typedef unsigned char uchar_t;
  51. #endif
  52.  
  53. #include "if.h"
  54. #include "prtypes.h"
  55. #include <plevent.h>
  56. #include <prtypes.h>
  57. #include "libevent.h"
  58.  
  59. extern void append_to_output_file(char* data, int len);
  60.  
  61. /* =========================================================================
  62.    All this junk is just to get it to link.
  63.    =========================================================================
  64.  */
  65.  
  66. void * FE_SetTimeout(TimeoutCallbackFunction func, void * closure,
  67.                      uint32 msecs) { return 0; }
  68. void FE_ClearTimeout(void *timer_id) {}
  69. void XP_Trace(const char * format, ...) {}
  70. void FE_ImageDelete(IL_Image *portableImage) {}
  71. int32 NET_GetMemoryCacheSize(void) { return 1000000; }
  72. int32 NET_GetMaxMemoryCacheSize(void) { return 1000000; }
  73. void NET_FreeURLStruct(URL_Struct * URL_s) {}
  74. int NET_InterruptWindow(MWContext * window_id) {return 0;}
  75. URL_Struct *NET_CreateURLStruct(const char *url, NET_ReloadMethod reload) { return 0; }
  76. History_entry *  SHIST_GetCurrent(History * hist) { return 0; }
  77. int NET_GetURL (URL_Struct * URL_s, FO_Present_Types output_format,
  78.         MWContext * context, Net_GetUrlExitFunc* exit_routine) 
  79. { return -1; }
  80. Bool LO_BlockedOnImage(MWContext *c, LO_ImageStruct *image) { return FALSE; }
  81. Bool NET_IsURLInDiskCache(URL_Struct *URL_s) {return TRUE;}
  82. XP_Bool NET_IsLocalFileURL(char *address) {return TRUE;}
  83.  
  84. NET_StreamClass * NET_StreamBuilder (FO_Present_Types  format_out,
  85.                      URL_Struct *anchor, MWContext *window_id)
  86. { return 0; }
  87.  
  88. Bool NET_AreThereActiveConnectionsForWindow(MWContext * window_id)
  89. { return FALSE; }
  90. Bool NET_AreThereStoppableConnectionsForWindow(MWContext * window_id)
  91. { return FALSE; }
  92. void LO_RefreshAnchors(MWContext *context) { }
  93. void GH_UpdateGlobalHistory(URL_Struct * URL_s) { }
  94. char * NET_EscapeHTML(const char * string) { return (char *)string; }
  95. Bool LO_LocateNamedAnchor(MWContext *context, URL_Struct *url_struct,
  96.               int32 *xpos, int32 *ypos) { return FALSE; }
  97. Bool LO_HasBGImage(MWContext *context) {return FALSE; }
  98.  
  99. void FE_UpdateStopState(MWContext *context) {}
  100.  
  101. void
  102. FE_Alert (MWContext *context, const char *message) {}
  103.  
  104. void ET_RemoveWindowContext(MWContext *context, ETVoidPtrFunc fn,
  105.                 void *data) { }
  106.  
  107. extern int il_first_write(NET_StreamClass *stream, const unsigned char *str, int32 len);
  108.  
  109. void fe_ReLayout (MWContext *context, NET_ReloadMethod force_reload) {}
  110.  
  111. char *XP_GetBuiltinString(int16 i);
  112.  
  113. char *
  114. XP_GetString(int16 i)
  115. {
  116.     return XP_GetBuiltinString(i);
  117. }
  118.  
  119. Bool
  120. NET_IsURLInMemCache(URL_Struct *URL_s)
  121. {
  122.     return FALSE;
  123. }
  124.  
  125.  
  126.  
  127. /* =========================================================================
  128.    Now it gets REALLY nasty.
  129.    =========================================================================
  130.  */
  131.  
  132. struct image {
  133.   int width, height;
  134.   char *color_bits;
  135.   char *mono_bits;
  136.   char *mask_bits;
  137. };
  138.  
  139. int total_images = 0;
  140. struct image images[500] = { { 0, }, };
  141.  
  142. int total_colors;
  143. IL_IRGB cmap[256];
  144.  
  145. char* current_file = NULL;
  146.  
  147. int num_frames_small = 0;
  148. int width_small      = 0;
  149. int height_small     = 0;
  150.  
  151. int num_frames_large = 0;
  152. int width_large      = 0;
  153. int height_large     = 0;
  154.  
  155. int in_anim = 0;
  156. int inactive_icon_p = 0;
  157. int anim_frames[100] = { 0, };
  158.  
  159. XP_Bool sgi_p = FALSE;
  160.  
  161. static unsigned char *bitrev = 0;
  162.  
  163.  
  164. /*
  165.  * warn
  166.  */
  167. void
  168. warn(char* msg)
  169. {
  170.     fprintf(stderr, "Warning: %s: %s\n", current_file, msg);
  171. }
  172.  
  173.  
  174. /*
  175.  * error
  176.  */
  177. void
  178. error(char* msg)
  179. {
  180.     fprintf(stderr, "Error: %s: %s\n", current_file, msg);
  181.  
  182.     exit(1);
  183. }
  184.  
  185.  
  186. /*
  187.  * init_reverse_bits
  188.  */
  189. static void
  190. init_reverse_bits(void)
  191. {
  192.   if(!bitrev) 
  193.     {
  194.       int i, x, br;
  195.       bitrev = (unsigned char *)XP_ALLOC(256);
  196.       for(i=0; i<256; i++) 
  197.         {
  198.           br = 0;
  199.           for(x=0; x<8; x++) 
  200.             {
  201.               br = br<<1;
  202.               if(i&(1<<x))
  203.                 br |= 1;
  204.             }
  205.           bitrev[i] = br;
  206.         }
  207.     }
  208. }
  209.  
  210.  
  211. typedef enum {INITIAL_STATE, LARGE_STATE, SMALL_STATE, ERROR_STATE} image_state;
  212.  
  213.  
  214. /*
  215.  * image_size
  216.  * This routine is registered with the image library to be invoked
  217.  * when it has determined the size of the image that it is processing.
  218.  * Sets the size of the image, and allocates the appropriate memory.
  219.  */
  220. int
  221. image_size (MWContext *context, IL_ImageStatus message,
  222.         IL_Image *il_image, void *data)
  223. {
  224.   static image_state state = INITIAL_STATE;
  225.  
  226.   switch ( state ) {
  227.     case INITIAL_STATE:
  228.       printf("First large frame is %s.\n", current_file);
  229.       printf("Size is %d by %d pixels.\n", il_image->width, il_image->height);
  230.       num_frames_large++;
  231.       width_large = il_image->width;
  232.       height_large = il_image->height;
  233.       state = LARGE_STATE;
  234.       break;
  235.     case LARGE_STATE:
  236.       if ( il_image->width == width_large &&
  237.            il_image->height == height_large ) {
  238.         if ( num_frames_large < MAX_ANIM_FRAMES ) {
  239.           num_frames_large++;
  240.           printf("Reading large frame %d...\n", num_frames_large);
  241.         } else {
  242.           warn("Ignoring.  Too many frames for animation.");
  243.         }
  244.       } else {
  245.         printf("First small frame is %s.\n", current_file);
  246.         printf("Size is %d by %d pixels.\n", il_image->width, il_image->height);
  247.         num_frames_small++;
  248.         width_small = il_image->width;
  249.         height_small = il_image->height;
  250.         state = SMALL_STATE;
  251.       }
  252.       break;
  253.     case SMALL_STATE:
  254.       if ( il_image->width == width_small &&
  255.            il_image->height == height_small ) {
  256.         if ( num_frames_small < MAX_ANIM_FRAMES ) {
  257.           num_frames_small++;
  258.           printf("Reading small frame %d...\n", num_frames_small);
  259.         } else {
  260.           warn("Ignoring.  Too many frames for animation.");
  261.         }
  262.       } else {
  263.         error("Bad size.  Animation frames must have the same size.\n");
  264.         state = ERROR_STATE;
  265.       }
  266.       break;
  267.     case ERROR_STATE:
  268.       break;
  269.     default:
  270.       error("Unexpected error.  Reached bad switch.\n");
  271.       break;
  272.   }
  273.  
  274.   if (il_image->bits)
  275.     free (il_image->bits);
  276.  
  277.   il_image->bits = malloc (il_image->widthBytes * il_image->height);
  278.   memset (il_image->bits, ~0, (il_image->widthBytes * il_image->height));
  279.   if (!il_image->mask && il_image->transparent)
  280.     {
  281.       int size = il_image->maskWidthBytes * il_image->height;
  282.       il_image->mask = malloc (size);
  283.       memset (il_image->mask, ~0, size);
  284.     }
  285.  
  286.   return 0;
  287. }
  288.  
  289.  
  290. /*
  291.  * print_image
  292.  */
  293. void
  294. print_image(IL_Image* il_image)
  295. {
  296.     printf("---------------------------------------------\n");
  297.     printf("il_image->width             = %d\n", il_image->width);
  298.     printf("il_image->height            = %d\n", il_image->height);
  299.     printf("il_image->widthBytes        = %d\n", il_image->widthBytes);
  300.     printf("il_image->maskWidthBytes    = %d\n", il_image->maskWidthBytes);
  301.     printf("il_image->depth             = %d\n", il_image->depth);
  302.     printf("il_image->bytesPerPixel     = %d\n", il_image->bytesPerPixel);
  303.     printf("il_image->colors            = %d\n", il_image->colors);
  304.     printf("il_image->unique_colors     = %d\n", il_image->unique_colors);
  305.     printf("il_image->validHeight       = %d\n", il_image->validHeight);
  306.     printf("il_image->lastValidHeight   = %d\n", il_image->lastValidHeight);
  307.     printf("il_image->has_mask          = %s\n", il_image->has_mask ? 
  308.                                                  "True" : "False");
  309.     printf("il_image->hasUniqueColormap = %s\n", il_image->hasUniqueColormap ? 
  310.                                                  "True" : "False");
  311. }
  312.  
  313.  
  314. /*
  315.  * get_color
  316.  */
  317. int
  318. get_color(uchar_t r, uchar_t g, uchar_t b)
  319. {
  320.   int i;
  321.  
  322. #ifdef DEBUG_username
  323.   printf("Trying to find %d %d %d... ", r, g, b);
  324. #endif
  325.  
  326.   for ( i = 0; i < total_colors; i++ ) {
  327.     if ( cmap[i].red   == r &&
  328.          cmap[i].green == g &&
  329.          cmap[i].blue  == b ) {
  330.       return i;
  331.     }
  332.   }
  333.  
  334.   if ( total_colors > 64 ) {
  335.     error("Animations can contain no more than 64 colors.\n");
  336.   }
  337.  
  338.   cmap[total_colors].red   = r;
  339.   cmap[total_colors].green = g;
  340.   cmap[total_colors].blue  = b;
  341.  
  342.   total_colors++;
  343.  
  344.   return (total_colors-1);
  345. }
  346.  
  347.  
  348. /*
  349.  * image_data
  350.  * This routine is registered with the image library.  It is invoked
  351.  * when the image library has image data to be processed.  The mono
  352.  * bits, mask bits and color bits are written to the output buffer.
  353.  */
  354. void
  355. image_data (MWContext *context, IL_ImageStatus message, IL_Image *il_image,
  356.         void *data)
  357. {
  358.   int row_parity;
  359.   unsigned char *s, *m, *scanline, *mask_scanline, *end;
  360.  
  361. #ifdef DEBUG_username
  362.   print_image(il_image);
  363. #endif
  364.  
  365.   if (message != ilComplete) abort ();
  366.   images[total_images].width = il_image->width;
  367.   images[total_images].height = il_image->height;
  368.   if (il_image->depth == 1)
  369.     images[total_images].mono_bits = il_image->bits;
  370.   else
  371.     images[total_images].color_bits = il_image->bits;
  372.   if (il_image->mask)
  373.     images[total_images].mask_bits = il_image->mask;
  374.  
  375.   if (il_image->depth == 1)
  376.     return;
  377.   if (il_image->depth != 32) {
  378.     error("Color image depth not 32.\n");
  379.   }
  380.  
  381.   /* Generate monochrome icon from color data. */
  382.   scanline = il_image->bits;
  383.   mask_scanline = il_image->mask;
  384.   end = scanline + (il_image->widthBytes * il_image->height);
  385.   row_parity = 0;
  386.       
  387.   while (scanline < end)
  388.     {
  389.       unsigned char *scanline_end = scanline + (il_image->width * 4);
  390.       int luminance, pixel;
  391.       int bit = 0;
  392.       uchar_t byte = 0;
  393.  
  394.       row_parity ^= 1;
  395.       for (m = mask_scanline, s = scanline; s < scanline_end; s += 4)
  396.         {
  397.           unsigned char r = s[3];
  398.           unsigned char g = s[2];
  399.           unsigned char b = s[1];
  400.  
  401.           luminance = (0.299 * r) + (0.587 * g) + (0.114 * b);
  402.  
  403.           pixel =
  404.             ((luminance < 128))                      ||
  405.             ((r ==  66) && (g == 154) && (b == 167)); /* Magic: blue */
  406.           byte |= pixel << bit++;
  407.  
  408.           if ((bit == 8) || ((s + 4) >= scanline_end)) {
  409.             /* Handle transparent areas of the icon */
  410.             if (il_image->mask)
  411.               byte &= bitrev[*m++];
  412.  
  413.             append_to_output_file((char*) &byte, 1);
  414.  
  415.             bit = 0;
  416.             byte = 0;
  417.           }
  418.         }
  419.       scanline += il_image->widthBytes;
  420.       mask_scanline += il_image->maskWidthBytes;
  421.     }
  422.  
  423.   /* Mask data */
  424.   if (il_image->mask)
  425.     {
  426.       scanline = il_image->mask;
  427.       end = scanline + (il_image->maskWidthBytes * il_image->height);
  428.       for (;scanline < end; scanline += il_image->maskWidthBytes)
  429.         {
  430.           unsigned char *scanline_end = scanline + ((il_image->width + 7) / 8);
  431.           for (s = scanline; s < scanline_end; s++)
  432.             {
  433.               append_to_output_file((char*) &(bitrev[*s]), 1);
  434.             }
  435.         }
  436.     }
  437.   else
  438.     {
  439.       append_to_output_file(0, (il_image->width+7)/8*(il_image->height));
  440.     }
  441.  
  442.   /* Color icon */
  443.  
  444.   scanline = il_image->bits;
  445.   end = scanline + (il_image->widthBytes * il_image->height);
  446.   for (;scanline < end; scanline += il_image->widthBytes)
  447.     {
  448.       unsigned char *scanline_end = scanline + (il_image->width * 4);
  449.       for (s = scanline; s < scanline_end; s += 4)
  450.         {
  451.           unsigned char r = s[3];
  452.           unsigned char g = s[2];
  453.           unsigned char b = s[1];
  454.           int j;
  455.           uchar_t byte;
  456.           j = get_color(r, g, b);
  457.           byte = (uchar_t) j;
  458.           append_to_output_file((char*) &byte, 1);
  459.  
  460. #ifdef DEBUG_username
  461.           for (j = 0; j < total_colors; j++)
  462.             if (r == cmap[j].red &&
  463.                 g == cmap[j].green &&
  464.                 b == cmap[j].blue)
  465.               {
  466.                 byte = (uchar_t) j;
  467.                 append_to_output_file((char*) &byte, 1);
  468.                 goto DONE;
  469.               }
  470.           error("Error allocated colors.\n");
  471.         DONE:
  472.           ;
  473. #endif
  474.         }
  475.     }
  476.  
  477.   if (il_image->bits) free (il_image->bits);
  478.   il_image->bits = 0;
  479.   if (il_image->mask) free (il_image->mask);
  480.   il_image->mask = 0;
  481. }
  482.  
  483.  
  484. /*
  485.  * set_title
  486.  * A no-op.
  487.  */
  488. void
  489. set_title (MWContext *context, char *title)
  490. {
  491. }
  492.  
  493.  
  494. /*
  495.  * do_file
  496.  * Process an image file.
  497.  */
  498. void
  499. do_file (char *file)
  500. {
  501.   static int counter = 0;
  502.   FILE *fp;
  503.   char *data;
  504.   int size;
  505.   NET_StreamClass *stream;
  506.   struct stat st;
  507.   char *s;
  508.  
  509.   URL_Struct *url;
  510.   il_container *ic;
  511.   il_process *proc;
  512.   MWContext cx;
  513.   ContextFuncs fns;
  514.   IL_IRGB trans;
  515.  
  516.   memset (&cx, 0, sizeof(cx));
  517.   memset (&fns, 0, sizeof(fns));
  518.   
  519.   url = XP_NEW_ZAP (URL_Struct);
  520.   proc = XP_NEW_ZAP (il_process);
  521.  
  522.   url->address = strdup("\000\000");
  523.   cx.funcs = &fns;
  524.  
  525.   fns.ImageSize = image_size;
  526.   fns.ImageData = image_data;
  527.   fns.SetDocTitle = set_title;
  528.  
  529.   {
  530.     /* make a container */
  531.     ic = XP_NEW_ZAP(il_container);
  532.     ic->hash = 0;
  533.     ic->urlhash = 0;
  534.     ic->cx = &cx;
  535.     ic->forced = 0;
  536.  
  537.     ic->image = XP_NEW_ZAP(IL_Image);
  538.  
  539.     ic->next = 0;
  540.     ic->ip = proc;
  541.     cx.imageProcess = proc;
  542.  
  543.     ic->state = IC_START;
  544.   }
  545.  
  546.   url->fe_data = ic;
  547.  
  548.   ic->clients = XP_NEW_ZAP(il_client);
  549.   ic->clients->cx = &cx;
  550.  
  551.   if ( stat (file, &st) ) {
  552.     perror(file);
  553.     exit(errno);
  554.   }
  555.  
  556.   if ( !S_ISREG(st.st_mode) ) {
  557.     fprintf(stderr, "%s:  Not a plain file.\n", file);
  558.     exit(1);
  559.   }
  560.  
  561.   size = st.st_size;
  562.  
  563.   data = (char *) malloc (size + 1);
  564.   fp = fopen (file, "r");
  565.   fread (data, 1, size, fp);
  566.   fclose (fp);
  567.  
  568.   current_file = strdup(file);
  569.  
  570.   s = strrchr (file, '.');
  571.   if (s) *s = 0;
  572.   s = strrchr (file, '/');
  573.   if (s)
  574.     s++;
  575.   else
  576.     s = file;
  577.  
  578.   if (in_anim && strncmp (s, "Anim", 4))
  579.     /* once you've started anim frames, don't stop. */
  580.     abort ();
  581.  
  582.   if ((!strcmp (s, "AnimSm00") || !strcmp (s, "AnimHuge00")) ||
  583.       ((!strcmp (s, "AnimSm01") || !strcmp (s, "AnimHuge01")) &&
  584.        (!in_anim ||
  585.     anim_frames[in_anim-1] > 1)))
  586.     {
  587.       char *s2;
  588.  
  589.       s2 = s - 2;
  590.       while (s2 > file && *s2 != '/')
  591.     s2--;
  592.       s[-1] = 0;
  593.       if (*s2 == '/')
  594.     s2++;
  595.  
  596.       in_anim++;
  597.     }
  598.  
  599.   if (in_anim)
  600.     {
  601.       if (strncmp (s, "Anim", 4)) abort ();
  602.       anim_frames[in_anim-1]++;
  603.     }
  604.   else
  605.     {
  606.       char *s2 = s;
  607.       while (*s2)
  608.     {
  609.       if (*s2 == '.') *s2 = '_';
  610.       s2++;
  611.     }
  612.     }
  613.  
  614.   trans.red = trans.green = trans.blue = 0xC0;
  615.  
  616.   cx.colorSpace = NULL;
  617.  
  618.   IL_EnableTrueColor (&cx, 32,
  619. #if defined(IS_LITTLE_ENDIAN)
  620.               24, 16, 8,
  621. #elif defined(IS_BIG_ENDIAN)
  622.               0, 8, 16,
  623. #else
  624.   ERROR!  Endianness unknown.
  625. #endif
  626.               8, 8, 8,
  627.               &trans, FALSE);
  628.  
  629.   ic->cs = cx.colorSpace;
  630.   /*IL_SetPreferences (&cx, FALSE, ilClosestColor);*/
  631.   IL_SetPreferences (&cx, FALSE, ilDither);/* XXXM12N Replace with
  632.                                              IL_SetDisplayMode. */
  633.   url->address[0] = counter++;
  634.   stream = IL_NewStream (FO_PRESENT,
  635.              (strstr (current_file, ".gif") ? (void *) IL_GIF :
  636.               strstr (current_file, ".jpg") ? (void *) IL_JPEG :
  637.               strstr (current_file, ".jpeg") ? (void *) IL_JPEG :
  638.               strstr (current_file, ".xbm") ? (void *) IL_XBM :
  639.               (void *) IL_GIF),
  640.              url, &cx);
  641.   if ( stream->put_block (stream, data, size) < 0 ) {
  642.     error("Couldn't decode file.\n");
  643.   }
  644.  
  645.   stream->complete (stream);
  646.  
  647.   free(current_file);
  648.   free (data);
  649.  
  650.   total_images++;
  651. }
  652.  
  653.  
  654. uchar_t* output_buf = NULL;
  655. int output_max_len = 0;
  656. int output_len = 0;
  657.  
  658.  
  659. /*
  660.  * CHUNKSIZE should be 1024 or something, but make
  661.  * it small to make sure it works.
  662.  */
  663. #define CHUNKSIZE 64
  664.  
  665.  
  666. /*
  667.  * append_to_output_file
  668.  * Append the given data to the output buffer.  If the resulting data
  669.  * is too large for the currently allocated output buffer, first allocate
  670.  * additional space.
  671.  */
  672. void
  673. append_to_output_file(char* data, int len)
  674. {
  675.     while ( output_buf == NULL || output_len + len >= output_max_len ) {
  676.         output_max_len+= CHUNKSIZE;
  677.         output_buf = (char*) realloc(output_buf, output_max_len);
  678.     }
  679.  
  680.     if ( data ) {
  681.       memcpy(output_buf+output_len, data, len);
  682.     } else {
  683.       memset(output_buf+output_len, 0xff, len);
  684.     }
  685.  
  686.     output_len+= len;
  687. }
  688.  
  689.  
  690. #define ANIMATION_FILENAME "animation.dat"
  691.  
  692.  
  693. /*
  694.  * usage
  695.  */
  696. void
  697. usage(char* progname)
  698. {
  699.     fprintf(stderr, "Usage: %s large-animation-files small-animation-files\n",
  700.                     progname);
  701. }
  702.  
  703.  
  704. /*
  705.  * main
  706.  * Process each file given on the command line.
  707.  */
  708. int
  709. main (int argc, char* argv[])
  710. {
  711.   int i;
  712.   FILE* anim_file;
  713.  
  714.   init_reverse_bits();
  715.  
  716.   if ( argc < 2 ) {
  717.     usage(argv[0]);
  718.     exit(1);
  719.   }
  720.  
  721.   for (i = 1; i < argc; i++) {
  722.     char *filename = argv[i];
  723.     inactive_icon_p = (strstr(filename, ".i.gif") != NULL);
  724.     do_file (filename);
  725.   }
  726.  
  727.   if ( (anim_file = fopen(ANIMATION_FILENAME, "w")) == NULL ) {
  728.     perror(ANIMATION_FILENAME);
  729.     exit(errno);
  730.   }
  731.  
  732.   fprintf(anim_file, "%d %d %d\n", num_frames_large, width_large, height_large);
  733.   fprintf(anim_file, "%d %d %d\n", num_frames_small, width_small, height_small);
  734.   fprintf(anim_file, "%d\n", total_colors);
  735.  
  736.   for ( i = 0; i < total_colors; i++ ) {
  737.     fprintf(anim_file, "%x %x %x\n", cmap[i].red * 257,
  738.                                      cmap[i].green * 257,
  739.                                      cmap[i].blue * 257);
  740.   }
  741.  
  742.   if ( output_buf == NULL ) {
  743.     error("No image data to write.\n");
  744.   }
  745.  
  746.   if ( fwrite(output_buf, sizeof(uchar_t), output_len, anim_file) != 
  747.         output_len) {
  748.     perror(ANIMATION_FILENAME);
  749.     exit(errno);
  750.   }
  751.  
  752.   if ( fclose(anim_file) != 0 ) {
  753.     perror(ANIMATION_FILENAME);
  754.     exit(errno);
  755.   }
  756.  
  757.   printf("Wrote %d large frames, %d small frames.\n", num_frames_large, 
  758.                                                       num_frames_small);
  759.  
  760.   printf("%d colors\n", total_colors);
  761.  
  762.   fprintf(stderr, "Successfully wrote '%s'\n", ANIMATION_FILENAME);
  763.  
  764.   return 0;
  765. }
  766.  
  767.  
  768.