home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Graphics / Anim2gif-GUI / WhirlGif / src.202 / whirlgif.c < prev    next >
C/C++ Source or Header  |  1997-07-07  |  18KB  |  827 lines

  1.   
  2. /*
  3.  * whirlgif.c
  4.  *
  5.  * Copyright (C) 1995,1996 by Kevin Kadow (kadokev@msg.net)
  6.  * 
  7.  * Based on txtmerge.c
  8.  * Copyright (C) 1990,1991,1992,1993 by Mark Podlipec. 
  9.  * All rights reserved.
  10.  *
  11.  * This software may be freely copied, modified and redistributed
  12.  * without fee provided that this copyright notice is preserved 
  13.  * intact on all copies and modified copies.
  14.  * 
  15.  * There is no warranty or other guarantee of fitness of this software.
  16.  * It is provided solely "as is". The author(s) disclaim(s) all
  17.  * responsibility and liability with respect to this software's usage
  18.  * or its effect upon hardware or computer systems.
  19.  *
  20.  */
  21.  /*
  22.   * Description:
  23.   *
  24.   * This program reads in a sequence of single-image GIF format files and
  25.   * outputs a single multi-image GIF file, suitable for use as an animation.
  26.   *
  27.   * TODO:
  28.   *
  29.   * More options for dealing with the colormap
  30.   *
  31.   * Eventually, I'd like to have this program compare the current image
  32.   * with the previous image and check to see if only a small section of
  33.   * the screen changed from the previous image. Worth a shot.
  34.   */
  35.  
  36.  /*
  37.   * Rev 2.02    07Jul97 Hannu Nevalainen
  38.   *     -disp was always "none"
  39.   * Rev 2.01    31Aug96 Kevin Kadow
  40.   *    disposal
  41.   * Rev 2.00    05Feb96 Kevin Kadow
  42.   *    transparency, gif comments,
  43.   * Rev 1.10    29Jan96 Kevin Kadow
  44.   *    first release of whirlgif
  45.   *
  46.   * txtmerge:
  47.   * Rev 1.00    23Jul91    Mark Podlipec
  48.   *    creation
  49.   * Rev 1.01    08Jan92    Mark Podlipec
  50.   *     use all colormaps, not just 1st.
  51.   *
  52.   * 
  53.   */
  54. #define DA_REV 2.02
  55.  
  56. #include <stdio.h>
  57. #include <stdlib.h>
  58. #ifdef _USE_STRINGS_H
  59. #include <strings.h>
  60. #else
  61. #include <string.h>
  62. #endif
  63.  
  64. #include "whirlgif.h"
  65.  
  66. #define MAXVAL  4100            /* maxval of lzw coding size */
  67. #define MAXVALP 4200
  68.  
  69. /*
  70.  * Set some defaults, these can be changed on the command line
  71.  */
  72. unsigned int loop=DEFAULT_LOOP,loopcount=0,
  73.     use_colormap=DEFAULT_USE_COLORMAP,
  74.     debug_flag=0,
  75.     verbose=0;
  76.  
  77. int imagex = 0;
  78. int imagey = 0;
  79. int imagec = 0;
  80.  
  81. /* global settings for offset, transparency */
  82. Global global;
  83.  
  84. GIF_Color gif_cmap[256];
  85.  
  86. ULONG GIF_Get_Code();
  87. void GIF_Decompress();
  88. void GIF_Get_Next_Entry();
  89. void GIF_Add_To_Table();
  90. void GIF_Send_Data();
  91. void GIF_Clear_Table();
  92. void GIF_Screen_Header();
  93. void GIF_Image_Header();
  94. void GIF_Read_File();
  95. void GIF_Comment();
  96. void GIF_Loop();
  97. void GIF_GCL();
  98. void Calc_Trans();
  99. void set_offset();
  100.  
  101. GIF_Screen_Hdr gifscrn;
  102. GIF_Image_Hdr gifimage;
  103. GIF_Table table[MAXVALP];
  104.  
  105. ULONG root_code_size,code_size,CLEAR,EOI,INCSIZE;
  106. ULONG nextab;
  107. ULONG gif_mask[16] = {1,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,0,0};
  108. ULONG gif_ptwo[16] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,0,0};
  109.  
  110.  
  111. UBYTE gif_buff[MAXVALP];
  112. ULONG gif_block_size;
  113. int num_bits,bits;
  114.  
  115. int pic_i;
  116. char gif_file_name[BIGSTRING];
  117. int screen_was_last;
  118.  
  119.  
  120. void TheEnd()
  121. {
  122.  exit(0);
  123. }
  124.  
  125. void TheEnd1(p)
  126. char *p;
  127. {
  128.  fprintf(stderr,"%s",p);
  129.  TheEnd();
  130. }
  131.  
  132. Usage()
  133. {
  134.   fprintf(stderr,"\nUsage: whirlgif [-v] [-off x,y] [-o outfile] [-loop [count]] [-time #delay]\n");
  135.   fprintf(stderr,"\t[-debug] [-disp none | not | back | prev ] [-u 0 | 1 | false | true ]\n");
  136.   fprintf(stderr,"\t[ -i listfile] [ -trans index] file1 file2 ...\n");
  137.   exit(0);
  138. }
  139.  
  140. main(argc,argv)
  141. int argc;
  142. char *argv[];
  143. {
  144.  FILE * infile, *fout;
  145.  char temp[BIGSTRING];
  146.  int ret,i;
  147.  int count=0;
  148.  
  149.  fprintf(stderr,"whirlgif Rev %2.2f (C) 1996 by Kevin Kadow\n",DA_REV);
  150.  fprintf(stderr,"                  (C) 1991,1992 by Mark Podlipec\n");
  151.  
  152.  if (argc < 2) Usage();
  153.  
  154.  /* set global values */
  155.  screen_was_last = FALSE;
  156.  global.trans.type=TRANS_NONE;
  157.  global.trans.valid=FALSE;
  158.  global.time=DEFAULT_TIME;
  159.  global.left=0;
  160.  global.top=0;
  161.  global.disposal=DEFAULT_DISPOSAL;
  162.  
  163.  
  164.  fout=stdout;
  165.  i = 1;
  166.  while( i < argc)
  167.  {
  168.   char *p;
  169.   p = argv[i];
  170.   /*fprintf(stderr,"Option: %s\n",p);*/
  171.   if ( (p[0] == '-') || (p[0] == '+') )
  172.   { 
  173.    ++p; /* strip off the - */
  174.    switch(p[0])
  175.    {
  176.     case 'v':    /* Give lots of information */
  177.             verbose++;
  178.             i++;
  179.         fprintf(stderr,"Verbose output\n");
  180.         break;
  181.  
  182.     case 'd':    /* either Debug mode or disposal setting */
  183.         i++;
  184.         if(!strncmp("disp",p,4)) {
  185.             p=argv[i];
  186.             if(!strcmp("none",p)) 
  187.                global.disposal = DISP_NONE;
  188.             else if(!strcmp("not",p)) 
  189.                global.disposal = DISP_NOT;
  190.             else if(!strcmp("back",p)) 
  191.                global.disposal = DISP_BACK;
  192.             else if(!strcmp("prev",p)) 
  193.                global.disposal = DISP_PREV;
  194.             else global.disposal = DISP_NONE;
  195.               if(verbose) fprintf(stderr,"Disposal method set to %d (%s)\n",global.disposal,p);
  196.         }
  197.         else {
  198.             debug_flag++;
  199.             fprintf(stderr,"DEBUG: Debug Level %d\n",debug_flag);
  200.         }
  201.         i++;
  202.         break;
  203.  
  204.     case 'l':    /* Enable looping */
  205.         loop=TRUE;
  206.         i++;
  207.         if(*argv[i] !='-') {
  208.           /* a loop count was given */
  209.           loopcount=atoi(argv[i++]);
  210.           if(verbose) fprintf(stderr,"Loop %d times\n",loopcount);
  211.           }
  212.         else {
  213.           /* default to infinite loop */
  214.           loopcount=0;
  215.           if(verbose) fputs("Looping enabled\n",stderr);
  216.           }
  217.         break;
  218.  
  219.     case 'u':    /* Use colormap? true or false */
  220.         i++;
  221.         if(atoi(argv[i]) || !strcmp("true",argv[i])) use_colormap=1;
  222.         else use_colormap=0;
  223.         i++;
  224.         break;
  225.  
  226.     case 't':    /* either time or transparent */
  227.         i++;
  228.         if(!strcmp("time",p)) {
  229.             /* Delay time in 1/100's of a second */
  230.             global.time=atoi(argv[i++]);
  231.               if(verbose) fprintf(stderr,"Time (re)set to %d\n",global.time);
  232.             }
  233.         else if(!strncmp("trans",p,4)) Calc_Trans(argv[i++]);
  234.         break;
  235.  
  236.     case 'o':    /* Output file - send output to a given filename */
  237.         i++;
  238.         if(!strncmp("off",p,3)) set_offset(argv[i]);
  239.         else
  240.         /* It must be 'output, so do that */
  241.         if(NULL==(fout=fopen(argv[i],"w")))
  242.             {
  243.             fprintf(stderr,"Cannot open %s for output\n",argv[i]);
  244.             exit(1);
  245.             }
  246.         i++;
  247.         break;
  248.     case 'i':    /* input file - file with a list of images */
  249.         i++;
  250.         if(NULL != (infile=fopen(argv[i],"r"))) {
  251.             while(fgets(gif_file_name,BIGSTRING,infile)) {
  252.                 strtok(gif_file_name,"\n");
  253.                   if(!count) GIF_Read_File(fout,gif_file_name,1);
  254.                   else       GIF_Read_File(fout,gif_file_name,0);
  255.                   count++;
  256.                 }
  257.             fclose(infile);
  258.             }
  259.         else fprintf(stderr,"Cannot read list file %s\n",argv[i]);
  260.         i++;
  261.         break;
  262.     default: 
  263.         Usage();
  264.         exit(0);
  265.         break;
  266.    }
  267.    continue;
  268.   }
  269.   /* Not an option, must be the name of an input file */
  270.   if(!count) GIF_Read_File(fout,argv[i],1);
  271.   else       GIF_Read_File(fout,argv[i],0);
  272.   count++;
  273.   i++;
  274.  }
  275.  /* We're done with all the options, finish up */
  276.  if(count >0)
  277.   {
  278.   fputc(';',fout); /* image separator */
  279.   sprintf(temp,"whirlgif %2.2f (C) kadokev@msg.net. %d images",DA_REV,count);
  280.   GIF_Comment(fout,temp);
  281.   }
  282.  
  283.  fclose(fout);
  284.  fprintf(stderr,"Processed %d files.\n",count);
  285.  exit(0);
  286. }
  287.  
  288.  
  289. /*
  290.  * Read a GIF file, outputting to fname as we go.
  291.  * It would be faster to read and write the individual blocks,
  292.  * but eventually we'd like to optimize based on changes from
  293.  * previous images(ie only a small section of the image changed.
  294.  */
  295. void
  296. GIF_Read_File(fout,fname,first_image)
  297. FILE * fout;
  298. char *fname;
  299. int first_image;
  300. {
  301.  FILE *fp;
  302.  int ret,i,exit_flag;
  303.  
  304.  if ( (fp=fopen(fname,"r"))==0)
  305.  { 
  306.   fprintf(stderr,"Can't open %s for reading.\n",fname); 
  307.   TheEnd();
  308.  }
  309.  
  310.  GIF_Screen_Header(fp,fout,first_image);
  311.  
  312.  /*** read until  ,  separator */
  313.  do
  314.  {
  315.   i=fgetc(fp);
  316.   if ( (i<0) && feof(fp))
  317.   {
  318.    fclose(fp);
  319.    TheEnd1("GIF_Read_Header: Unexpected End of File\n");
  320.   }
  321.  } while(i != ',');
  322.  
  323.  if(first_image)
  324.   {
  325.    /* stuff we only do once */
  326.    if(loop) GIF_Loop(fout,loopcount);
  327.    }
  328.  if(global.time||(global.trans.type!=TRANS_NONE && global.trans.valid))
  329.     GIF_GCL(fout,global.time);
  330.  
  331.  fputc(',',fout); /* image separator */
  332.  
  333.  GIF_Image_Header(fp,fout,first_image);
  334.  
  335.  /*FOO*/
  336.  
  337.  /*** Setup ACTION for IMAGE */
  338.  
  339.  GIF_Decompress(fp,fout,0);
  340.  fputc(0,fout);  /* block count of zero */
  341.  
  342.  fclose(fp);
  343. }
  344.  
  345. void GIF_Decompress(fp,fout)
  346. FILE *fp,*fout;
  347. {
  348.  register ULONG code,old;
  349.  
  350.  pic_i = 0;
  351.  bits=0;
  352.  num_bits=0;
  353.  gif_block_size=0;
  354.     /* starting code size of LZW */
  355.  root_code_size=(fgetc(fp) & 0xff); fputc(root_code_size,fout);
  356.  GIF_Clear_Table();                /* clear decoding symbol table */
  357.  
  358.  code=GIF_Get_Code(fp,fout);
  359.  
  360.  if (code==CLEAR) 
  361.  {
  362.   GIF_Clear_Table(); 
  363.   code=GIF_Get_Code(fp,fout);
  364.  }
  365.  /* write code(or what it currently stands for) to file */
  366.  GIF_Send_Data(code);   
  367.  old=code;
  368.  code=GIF_Get_Code(fp,fout);
  369.  do
  370.  {
  371.   if (table[code].valid==1)    /* if known code */
  372.   {
  373.        /* send it's associated string to file */
  374.     GIF_Send_Data(code);
  375.     GIF_Get_Next_Entry(fp);       /* get next table entry (nextab) */
  376.     GIF_Add_To_Table(old,code,nextab);  /* add old+code to table */
  377.     old=code;
  378.   }
  379.   else      /* code doesn't exist */
  380.   {
  381.     GIF_Add_To_Table(old,old,code);   /* add old+old to table */
  382.     GIF_Send_Data(code);
  383.     old=code;
  384.   }
  385.   code=GIF_Get_Code(fp,fout);
  386.   if (code==CLEAR)
  387.   { 
  388.    GIF_Clear_Table();
  389.    code=GIF_Get_Code(fp,fout);
  390.    GIF_Send_Data(code);
  391.    old=code;
  392.    code=GIF_Get_Code(fp,fout);
  393.   }
  394.  } while(code!=EOI);
  395. }
  396.  
  397. void GIF_Get_Next_Entry(fp)
  398. FILE *fp;
  399. {
  400.    /* table walk to empty spot */
  401.  while(  (table[nextab].valid==1)
  402.        &&(nextab<MAXVAL)
  403.       ) nextab++;
  404.  /* 
  405.   * Ran out of space?!  Something's gone sour...
  406.   */
  407.  if (nextab>=MAXVAL)    
  408.  { 
  409.   fprintf(stderr,"Error: GetNext nextab=%d\n",nextab);
  410.   fclose(fp);
  411.   TheEnd();
  412.  }
  413.  if (nextab==INCSIZE)   /* go to next table size (and LZW code size ) */
  414.  {
  415.    /* fprintf(stderr,"GetNext INCSIZE was %d ",nextab); */
  416.    code_size++; INCSIZE=(INCSIZE*2)+1;
  417.    if (code_size>=12) code_size=12;
  418. /*   fprintf(stderr,"<%d>",INCSIZE); */
  419.  }
  420.  
  421. }
  422. /*  body is associated string
  423.     next is code to add to that string to form associated string for
  424.     index
  425. */     
  426.  
  427. void GIF_Add_To_Table(body,next,index)
  428. register ULONG body,next,index;
  429. {
  430.  if (index>MAXVAL)
  431.  { 
  432.   fprintf(stderr,"Error index=%d\n",index);
  433.  }
  434.  else
  435.  {
  436.   table[index].valid=1;
  437.   table[index].data=table[next].first;
  438.   table[index].first=table[body].first;
  439.   table[index].last=body;
  440.  }
  441. }
  442.  
  443. void GIF_Send_Data(index)
  444. register int index;
  445. {
  446.  register int i,j;
  447.  i=0;
  448.  do         /* table walk to retrieve string associated with index */
  449.  { 
  450.   gif_buff[i]=table[index].data; 
  451.   i++;
  452.   index=table[index].last;
  453.   if (i>MAXVAL)
  454.   { 
  455.    fprintf(stderr,"Error: Sending i=%d index=%d\n",i,index);
  456.    TheEnd();
  457.   }
  458.  } while(index>=0);
  459.  
  460.  /* now invert that string since we retreived it backwards */
  461.  i--;
  462.  for(j=i;j>=0;j--)
  463.  {
  464.   /*pic[pic_i] = gif_buff[j] | gif_pix_offset;*/
  465.   pic_i++;
  466.  }
  467. }
  468.  
  469.  
  470. /* 
  471.  * initialize string table 
  472.  */
  473. void GIF_Init_Table()       
  474. {
  475.  register int maxi,i;
  476.  
  477. if (debug_flag) fprintf(stderr,"Initing Table...");
  478.  maxi=gif_ptwo[root_code_size];
  479.  for(i=0; i<maxi; i++)
  480.  {
  481.   table[i].data=i;   
  482.   table[i].first=i;
  483.   table[i].valid=1;  
  484.   table[i].last = -1;
  485.  }
  486.  CLEAR=maxi; 
  487.  EOI=maxi+1; 
  488.  nextab=maxi+2;
  489.  INCSIZE = (2*maxi)-1;
  490.  code_size=root_code_size+1;
  491. }
  492.  
  493.  
  494. /* 
  495.  * clear table 
  496.  */
  497. void GIF_Clear_Table()   
  498. {
  499.  register int i;
  500. if (debug_flag) fprintf(stderr,"Clearing Table...\n");
  501.  for(i=0;i<MAXVAL;i++) table[i].valid=0;
  502.  GIF_Init_Table();
  503. }
  504.  
  505. /*CODE*/
  506. ULONG GIF_Get_Code(fp,fout) /* get code depending of current LZW code size */
  507. FILE *fp,*fout;
  508. {
  509.  ULONG code;
  510.  register int tmp;
  511.  
  512.  while(num_bits < code_size)
  513.  {
  514.   /**** if at end of a block, start new block */
  515.   if (gif_block_size==0) 
  516.   {
  517.    tmp = fgetc(fp);
  518.    if (tmp >= 0 )
  519.    {
  520.     fputc(tmp,fout);
  521.     gif_block_size=(ULONG)(tmp);
  522.    }
  523.    else TheEnd1("EOF in data stream\n");
  524.   }
  525.  
  526.   tmp = fgetc(fp);   gif_block_size--;
  527.   if (tmp >= 0)
  528.   {
  529.    fputc(tmp,fout);
  530.    bits |= ( ((ULONG)(tmp) & 0xff) << num_bits );
  531.    num_bits+=8;
  532.   }
  533.   else TheEnd1("EOF in data stream\n");
  534.  }
  535.   
  536.  code = bits & gif_mask[code_size];
  537.  bits >>= code_size;
  538.  num_bits -= code_size; 
  539.  
  540.  
  541.  if (code>MAXVAL)
  542.  { 
  543.   fprintf(stderr,"\nError! in stream=%x \n",code); 
  544.   fprintf(stderr,"CLEAR=%x INCSIZE=%x EOI=%x code_size=%x \n",
  545.                                            CLEAR,INCSIZE,EOI,code_size); 
  546.   code=EOI;
  547.  }
  548.  
  549.  if (code==INCSIZE)
  550.  {
  551.   if (code_size<12)
  552.   {
  553.    code_size++; INCSIZE=(INCSIZE*2)+1;
  554.   }
  555.   else if (debug_flag) fprintf(stderr,"<13?>"); 
  556.  }
  557.  
  558.  return(code);
  559. }
  560.  
  561.  
  562. /* 
  563.  * read GIF header 
  564.  */
  565. void GIF_Screen_Header(fp,fout,first_time)
  566. FILE *fp,*fout;
  567. int first_time;
  568. {
  569.  int temp,i;
  570.  
  571.  for(i=0;i<6;i++)
  572.  {
  573.   temp = fgetc(fp);
  574.   if(i==4 && temp == '7') temp='9';
  575.   if (first_time==TRUE) fputc(temp,fout);
  576.  }
  577.  
  578.  gifscrn.width  = GIF_Get_Short(fp,fout,first_time);
  579.  gifscrn.height = GIF_Get_Short(fp,fout,first_time);
  580.  temp=fgetc(fp);                 if (first_time==TRUE) fputc(temp,fout);
  581.  gifscrn.m       =  temp & 0x80;
  582.  gifscrn.cres    = (temp & 0x70) >> 4;
  583.  gifscrn.pixbits =  temp & 0x07;
  584.  
  585.  gifscrn.bc  = fgetc(fp);
  586.  if (first_time==TRUE) 
  587.     {
  588.     /* we really should set the background color to the transparent color */
  589.     fputc(gifscrn.bc,fout);
  590.     }
  591.  
  592.  temp=fgetc(fp);                 if (first_time==TRUE) fputc(temp,fout);
  593.  imagec=gif_ptwo[(1+gifscrn.pixbits)];
  594.  
  595.  if (verbose)
  596.   fprintf(stderr,"Screen: %dx%dx%d m=%d cres=%d bkgnd=%d pix=%d\n",
  597.     gifscrn.width,gifscrn.height,imagec,gifscrn.m,gifscrn.cres,
  598.     gifscrn.bc,gifscrn.pixbits);
  599.  
  600.  if(global.trans.type==TRANS_RGB) global.trans.valid=0;
  601.  if (gifscrn.m)
  602.  {
  603.   for(i=0;i<imagec;i++)
  604.   {
  605.    gif_cmap[i].cmap.red   = temp = fgetc(fp); 
  606.            if (first_time==TRUE) fputc(temp,fout);
  607.    gif_cmap[i].cmap.green = temp = fgetc(fp); 
  608.            if (first_time==TRUE) fputc(temp,fout);
  609.    gif_cmap[i].cmap.blue  = temp = fgetc(fp); 
  610.            if (first_time==TRUE) fputc(temp,fout);
  611.  
  612.    if(global.trans.type==TRANS_RGB && !global.trans.valid)
  613.     if(global.trans.red==gif_cmap[i].cmap.red &&
  614.     global.trans.green==gif_cmap[i].cmap.green &&
  615.     global.trans.blue==gif_cmap[i].cmap.blue) {
  616.       if(debug_flag>1) fprintf(stderr," Transparent match at %d\n",i);
  617.         global.trans.map=i;
  618.     global.trans.valid=TRUE;
  619.     }
  620.   }
  621.  }
  622.  screen_was_last = TRUE;
  623. }
  624.  
  625. void GIF_Image_Header(fp,fout,first_time)
  626. FILE *fp,*fout;
  627. int first_time;
  628. {
  629.  int temp,tnum,i,r,g,b;
  630.  
  631.  gifimage.left   = GIF_Get_Short(fp,fout,1);
  632.  if(global.left) gifimage.left+=global.left;
  633.  
  634.  gifimage.top    = GIF_Get_Short(fp,fout,1);
  635.  if(global.top) gifimage.top+=global.top;
  636.  
  637.  gifimage.width  = GIF_Get_Short(fp,fout,1);
  638.  gifimage.height = GIF_Get_Short(fp,fout,1);
  639.  temp=fgetc(fp); 
  640.  
  641.  
  642.     
  643.  gifimage.i        = temp & 0x40;
  644.  gifimage.pixbits  = temp & 0x07;
  645.  gifimage.m        = temp & 0x80;
  646.  
  647.  /* this sets the local colormap bit to true */
  648.  if (screen_was_last && (first_time==FALSE)) temp |= 0x80;
  649.  
  650.  temp &= 0xf8;
  651.  temp |= gifscrn.pixbits;
  652.  fputc(temp,fout);
  653.  
  654.  imagex=gifimage.width;
  655.  imagey=gifimage.height;
  656.  tnum=gif_ptwo[(1+gifimage.pixbits)];
  657.  if (verbose)
  658.   fprintf(stderr,"Image: %dx%dx%d (%d,%d) m=%d i=%d pix=%d \n",
  659.     imagex,imagey,tnum,gifimage.left,gifimage.top,
  660.     gifimage.m,gifimage.i,gifimage.pixbits);
  661.  
  662.  /* if there is an image cmap, then use it */
  663.  
  664.  if (gifimage.m)
  665.  {
  666.   if(debug_flag) fprintf(stderr,"DEBUG:Transferring colormap of %d colors\n",
  667.             imagec);
  668.   for(i=0;i<tnum;i++)
  669.   {
  670.    gif_cmap[i].cmap.red   = r = fgetc(fp);
  671.    gif_cmap[i].cmap.green = g = fgetc(fp);
  672.    gif_cmap[i].cmap.blue  = b = fgetc(fp);
  673.    fputc(r,fout);
  674.    fputc(g,fout);
  675.    fputc(b,fout);
  676.   }
  677.  }  /* else if screen was last not 1st time */
  678.  else if (screen_was_last && (first_time==FALSE))
  679.  {
  680.   if(debug_flag>1) fprintf(stderr,"DEBUG:Writing colormap of %d colors\n",
  681.             imagec);
  682.   for(i=0;i<imagec;i++)
  683.   {
  684.    fputc(gif_cmap[i].cmap.red  ,fout);
  685.    fputc(gif_cmap[i].cmap.green,fout);
  686.    fputc(gif_cmap[i].cmap.blue ,fout);
  687.   }
  688.  }
  689.  screen_was_last = FALSE; 
  690. }
  691.  
  692.  
  693. /*
  694.  *
  695.  */
  696. int GIF_Get_Short(fp,fout,first_time)
  697. FILE *fp,*fout;
  698. int first_time;
  699. {
  700.  register int temp,tmp1;
  701.  temp=fgetc(fp);     if (first_time==TRUE) fputc(temp,fout);
  702.  tmp1=fgetc(fp);     if (first_time==TRUE) fputc(tmp1,fout);
  703.  return(temp|( (tmp1) << 8 ));
  704. }
  705.  
  706. void GIF_Comment(fout,string)
  707. FILE *fout;
  708. char *string;
  709. {
  710. if(!string || !strlen(string))
  711.         {
  712.         /* Bogus string */
  713.         if(debug_flag) fprintf(stderr,"GIF_Comment: invalid argument");
  714.         return;
  715.         }
  716. fputc(0x21,fout);
  717. fputc(0xFE,fout);
  718. fputs(string,fout);
  719. fputc(0,fout);
  720. }
  721.  
  722. /*
  723.  * Write a Netscape loop marker.
  724.  */
  725. void GIF_Loop(fout,repeats)
  726. FILE *fout;
  727. unsigned int repeats;
  728. {
  729. UBYTE low=0,high=0;
  730. if(repeats) {
  731.     /* non-zero repeat count- Netscape hasn't implemented this yet */
  732.     high=repeats / 256;
  733.     low=repeats % 256;
  734.     }
  735.  
  736. fputc(0x21,fout);
  737. fputc(0xFF,fout);
  738. fputc(0x0B,fout);
  739. fputs("NETSCAPE2.0",fout);
  740. fputc(0x03,fout);
  741. fputc(0x01,fout);
  742.  
  743. fputc(low,fout); /* the delay count - 0 for infinite */
  744. fputc(high,fout); /* second byte of delay count */
  745. fputc(0x00,fout); /* terminator */
  746.  
  747. if(verbose) fprintf(stderr,"Wrote loop extension\n");
  748. }
  749.  
  750. /*
  751.  * GIF_GCL - add a Control Label to set an inter-frame delay value.
  752.  */
  753. void GIF_GCL(fout,delay)
  754. FILE * fout;
  755. unsigned int delay;
  756. {
  757. UBYTE low=0,high=0,flag;
  758. if(delay) {
  759.     /* non-zero delay, figure out low/high bytes */
  760.     high=delay / 256;
  761.     low=delay % 256;
  762.     }
  763.  
  764. fputc(0x21,fout);
  765. fputc(0xF9,fout);
  766. fputc(0x04,fout);
  767.  
  768. flag = global.disposal <<2;
  769. if(delay) flag |=0x80;
  770. if(global.trans.valid) flag |=0x01;
  771. fputc(flag,fout);
  772.  
  773. fputc(low,fout); /* the delay speed - 0 is instantaneous */
  774. fputc(high,fout); /* second byte of delay count */
  775.  
  776. fputc(global.trans.map,fout);
  777. fputc(0,fout);
  778. if(debug_flag>1) {
  779.   fprintf(stderr,"GCL: delay %d",delay);
  780.   if(global.trans.valid) fprintf(stderr," Transparent: %d",global.trans.map);
  781.   fputc('\n',stderr);
  782.   }
  783. }
  784.  
  785.  
  786. void Calc_Trans(string)
  787. char * string;
  788. {
  789. if(string[0] != '#') {
  790.   global.trans.type=TRANS_MAP;
  791.   global.trans.map=atoi(string);
  792.   global.trans.valid=1;
  793.   }
  794. else
  795.   {
  796.   /* it's an RGB value */
  797.   int r,g,b;
  798.   string++;
  799.   if(3==sscanf(string,"%2x%2x%2x",&r,&g,&b)) {
  800.     global.trans.red=r;
  801.     global.trans.green=g;
  802.     global.trans.blue=b;
  803.     global.trans.type=TRANS_RGB;
  804.     if(debug_flag) fprintf(stderr,"Transparent RGB=(%x,%x,%x)\n",r,g,b);
  805.     }
  806.   }
  807. if(debug_flag) fprintf(stderr,"DEBUG:Calc_trans is %d\n",global.trans.type);
  808. }
  809.  
  810. void set_offset(string)
  811. char * string;
  812. {
  813. char *off_x,*off_y;
  814. off_x=(char *) strtok(string,",");
  815. off_y=(char *)strtok((char *)NULL,",");
  816. if(off_x && off_y) {
  817.     /* set the offset */
  818.     global.left=atoi(off_x);
  819.     global.top=atoi(off_y);
  820.     if(debug_flag>1) fprintf(stderr,"Offset changed to %d,%d\n",
  821.         global.left,global.top);
  822.     return;
  823.     }
  824. if(debug_flag>1) fprintf(stderr,"Couldn't parse offset values.\n");
  825. exit(1);
  826. }
  827.