/* GIF format  99,9,1 */

#include <stdio.h>
#define maxcol  102

FILE *fp;
int i,ixdim,iydim,lenbuf,kx,ky;	
int imax,imin,jmax,jmin;
char  *buf;
unsigned char icol;

void  jgdriv_ (ifunc, rbuf, nbuf, chr, lchr)
int   *ifunc, *nbuf, *lchr;
float rbuf[];
char  *chr;

{
      static float x,y;
      int j,k,n,i2;

         switch (*ifunc) {

/*--- IFUNC=1, Return device name ---------------------------------------*/

         case 1 :
            strcpy(chr,"JGIF    (jiang, GIF,2k*2k, pgpap(maxx,maxy))");
            *lchr = strlen(chr);
              break;

/*--- IFUNC=2, Return physical min and max for plot device, and range
               of color indices -----------------------------------------*/

         case 2 :
              rbuf[0] = 0.0;
              rbuf[1] = 2048.;
              rbuf[2] = 0.0;
              rbuf[3] = 2048.;
              rbuf[4] = 0.0;
              rbuf[5] = (float) maxcol;
              *nbuf = 6;
              break;

/*--- IFUNC=3, Return device resolution ---------------------------------*/

         case 3 :
              rbuf[0] = 75.;
              rbuf[1] = 75.;
              rbuf[2] = 1.;             /* Device coordinates per pixel */
              *nbuf = 3;
              break;

/*--- IFUNC=4, Return misc device info ----------------------------------*/

         case 4 :
              chr[0] = 'H'; /* interactive device */
              chr[1] = 'N'; /* cursor is available */
              chr[2] = 'N'; /* no dashed lines */
              chr[3] = 'N'; /* area fill available */
              chr[4] = 'N'; /* no fat lines */
              chr[5] = 'N'; /* rectangle fill available */
              chr[6] = 'N'; /* line of pixels available */
              chr[7] = 'N'; /* not used */
              chr[8] = 'N'; /* not used */
              chr[9] = 'N'; /* not used */
              *lchr = 10;
              break;

/*--- IFUNC=5, Return default file name ---------------------------------*/

         case 5 :
              strcpy (chr, "pgplot.gif");  /* Default name is NULL */
              *lchr = strlen(chr);
              break;

/*--- IFUNC=6, Return default physical size of plot ---------------------*/

         case 6 :
              rbuf[0] = 0.0;
              rbuf[1] = (float) (imax-imin);
              rbuf[2] = 0.0;
              rbuf[3] = (float) (jmax-jmin);
              *nbuf = 4;
              break;

/*--- IFUNC=7, Return misc defaults -------------------------------------*/

         case 7 :
              rbuf[0] = 1.0;
              *nbuf = 1;
              break;

/*--- IFUNC=8, Select plot ----------------------------------------------*/

         case 8 :
              break;

/*--- IFUNC=9, Open workstation -----------------------------------------*/

         case 9 :

       ixdim=2048.;
       iydim=2048.;
        imin=jmin=19;
        imax=ixdim-imin-1;
        jmax=iydim-jmin-1;
  
        fp=fopen("pgplot.gif","wb");
        if(fp==0){
          printf("cannot open file: pgplot.gif\n");
          rbuf[0]=1.;
	  rbuf[1]=0.;
	  *nbuf=-1;
	  fclose(fp);
        } else {
          rbuf[0]=0.;
	  rbuf[1]=1.;
        }
	if((buf=(char *)malloc(2048*2048))==0){
          printf(" memory alloc fail\n");
        } else jgbuf0(buf);

              break;

/*--- IFUNC=10, Close workstation ---------------------------------------*/
         case 10 :
	      fclose(fp);
              break;

/*--- IFUNC=11, Begin picture -------------------------------------------*/

         case 11 :
            ixdim = (int) (rbuf[0] + 0.5) + 2 * imin + 1;
            iydim = (int) (rbuf[1] + 0.5) + 2 * jmin + 1;
	    imax=ixdim-imin-1;
	    jmax=iydim-jmin-1;

            lenbuf=ixdim*iydim; 
	    for(i=0;i<lenbuf;i++)buf[i]=0;
              break;

/*--- IFUNC=12, Draw line -----------------------------------------------*/

         case 12 :

         /* Draw the line */

              gif01(1,rbuf);

              break;

/*--- IFUNC=13, Draw dot ------------------------------------------------*/

         case 13 :

              gif01(0,rbuf);

              break;

/*--- IFUNC=14, End picture ---------------------------------------------*/

         case 14 :

              gif04();
	if(buf!=0)free(buf);
              break;

/*--- IFUNC=15, Select color index --------------------------------------*/

         case 15 :

         /* Translate input */

              icol = (int) (rbuf[0] + 0.5);

         /* Check input for proper range */

              i=icol;
              if (i < 0 || i > maxcol) {
                 icol = 1;
                 rbuf[0] = (float) i;
                 }

              break;

/*--- IFUNC=16, Flush buffer. -------------------------------------------*/

         case 16 :
	 break;

/*--- IFUNC=18, Erase alpha screen. -------------------------------------*/

         case 18 :
	 break;

/*--- IFUNC-----------------------------------*/

         case 21 :
	 break;

/*--- IFUNC=26, Line of pixels ------------------------------------------*/

         case 26 :

              kx = (int) (rbuf[0] + 0.5) + imin;
              ky = (jmax - jmin) - (int) (rbuf[1] + 0.5) + jmin;
              ky=ky*ixdim+kx;
              for (i = 0; i <= *nbuf - 3; i++)
                 if(ky<lenbuf){
                    kx=(int) (rbuf[i+2] + 0.5);
                    buf[ky++]=kx;
                 }
         break;

/*--- IFUNC=27, box of pixels ------------------------------------------*/

         case 27 :
              kx = (int) (rbuf[0] + 0.5); 
              ky = (int) (rbuf[1] + 0.5);
	      i2=2;
	      n=*nbuf-2;
	      for (j = 0; j < n; j++){
                k=(ky+j)*ixdim+kx;
                for(i=0;i<n;i++){if(k<lenbuf)buf[k++]=rbuf[i2]+0.5; i2++; }
              }
         break;

/*--- IFUNC=?, ----------------------------------------------------------*/

         default :

              (void) fprintf (stderr,
                 "Unimplemented function in GIF device driver: %d\n",
                 *ifunc);
              *nbuf = -1;

              break;

              } /* End of switch */

         return;

} /* End of gidriv */


jgbuf0(buf)
char buf[];
{
  int i;
  for(i=0;i<2048*2048;i++)buf[i]=0;
}

gif01(line,rbuf)
int line;
float rbuf[];
{
  int length,i,i0,i1,j0,j1;
  float xinc,yinc,xp,yp,d;

  i0 = (int) (rbuf[0] + 0.5) + imin;
  j0 = (jmax - jmin) - (int) (rbuf[1] + 0.5) + jmin;
  i1 = (int) (rbuf[2] + 0.5) + imin;
  j1 = (jmax - jmin) - (int) (rbuf[3] + 0.5) + jmin;

  if(line>0){
    xp=i1-i0; if(xp<0)xp=-xp;
    yp=j1-j0; if(yp<0)yp=-yp;
    d=(xp>yp)?xp:yp; d++; 
    length=(int) d;  d= (float) length;
    xinc=(i1-i0)/d;
    yinc=(j1-j0)/d;
  } else {
    length=0; xinc=yinc=0.;
  }
  xp=i0;
  yp=j0;
  for(i=0;i<=length;i++){
    kx=xp+0.5; ky=yp+0.5;
    ky=ky*ixdim+kx;
    if(ky<lenbuf)buf[ky]=icol;
    xp+=xinc; yp+=yinc;
  }
}


#define LZW_MAXCODES  4096
#define TABLESIZES    4999
#define LZW_BitPlane     8                 /* 8 */
#define LZW_ClearCode  256                 /*256*/
#define LZW_BitCode     LZW_BitPlane+1
#define LZW_EofCode     LZW_ClearCode+1    

int  LZW_Encode;
int  LZW_RunBits;
int  LZW_MaxCodeSize;
int  LZW_ByteCount;
int  LZW_ShiftBits;
unsigned long LZW_TempCode;

unsigned char BlockBuf[256];
int  EncodeTable[4999];
int  PrefixTable[4999];
unsigned char SuffixTable[4999];
unsigned char ByteBuf[2592];          /* width */

int Code;
int Width, Height;
int PrefixCode, SuffixCode, RandomIndex, Val;
unsigned Dots, Rows;
/*
unsigned char head[72]= {
          0x47,0x49,0x46,0x38,0x39,0x61,0x1e,0x24,0x12,0x22,0xb3,0x00,0x00,
          0x00,0x00,0x00,0x1f,0x1f,0x1f,0x2f,0x2f,0x2f,0x3f,0x3f,0x3f,
          0x4f,0x4f,0x4f,0x5f,0x5f,0x5f,0x6f,0x6f,0x6f,0x7f,0x7f,0x7f,
          0x8f,0x8f,0x8f,0x9f,0x9f,0x9f,0xaf,0xaf,0xaf,0xbf,0xbf,0xbf,
          0xcf,0xcf,0xcf,0xdf,0xdf,0xdf,0xef,0xef,0xef,0xff,0xff,0xff,
          0x2c,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x03,0x04};
*/
short head1[7]={0x4947,0x3846,0x6139,0,0,0xb3,0};
short head2[5]={0,0,0,0,0};

static char ctable[256][3] =
       {
        {  0,  0,  0}, {255,255,255}, {255,  0,  0}, {  0,255,  0},
        {  0,  0,255}, {  0,255,255}, {255,  0,255}, {255,255,  0},
        {255,127,  0}, {127,255,  0}, {  0,255,127}, {  0,127,255},
        {127,  0,255}, {255,  0,127}, { 85, 85, 85}, {170,170,170},
        {1.0,1.0,1.0},
       };
static char kp=0;
gif04()
{
  int pp=0;
  char f1[12];
  strcpy(f1,"pgplot.gif");
  if(kp!=0){
    fclose(fp);
    strcpy(f1,"pgplot .gif");
    if(kp==10)kp+=7;
    f1[6]=kp+48;
    fopen(f1,"wb");
  } 
  printf("%d*%d  %s\n",ixdim,iydim,f1);
  kp++;
  for(i=15;i<=100;i++)
    ctable[i+1][0]= ctable[i+1][1]= ctable[i+1][2]= i*255/100;
  head1[3]=head2[2]=Width=ixdim;
  head1[4]=head2[3]=Height=iydim;
  if(LZW_BitPlane==8)head1[5]=0xf7;
  fwrite(head1,1,13,fp);
  fwrite(ctable,3,LZW_ClearCode,fp);
  fputc(0x2c,fp);
  head2[4]=LZW_BitPlane<<8;
  fwrite(head2,2,5,fp);

/*
  head[66]=Width;
  head[67]=Width>>8;
  head[68]=Height;
  head[69]=Height>>8;
  fwrite(head,1,72,fp);
*/
  	
  LZW_ByteCount = LZW_ShiftBits = LZW_TempCode = 0;
  ClearTable();
  Code = LZW_ClearCode;
  FillBlockBuf();
  for(Rows = 0; Rows < Height; Rows++)  {
    for(i=0;i<Width;i++)ByteBuf[i]=buf[pp++];
    if(Rows == 0) { PrefixCode = ByteBuf[0];  Dots = 1; }
    else Dots = 0;
    while( Dots < Width)  {
      SuffixCode = ByteBuf[Dots++];
      RandomIndex = PrefixCode ^ (SuffixCode << 4);
      if(RandomIndex == 0)  Val = 1;
      else Val = TABLESIZES - RandomIndex;
      while(1)  {
        if(EncodeTable[RandomIndex] == 0)  {
          Code = PrefixCode;
          FillBlockBuf();
          if(LZW_Encode == LZW_MAXCODES)  {
            Code = LZW_ClearCode;
            FillBlockBuf();
            ClearTable();
          }
          else  {
            if(LZW_Encode == LZW_MaxCodeSize)  {
              LZW_MaxCodeSize <<= 1;
              LZW_RunBits++;
            }
            PrefixTable[RandomIndex] = PrefixCode;
            SuffixTable[RandomIndex] = SuffixCode;
            EncodeTable[RandomIndex] = LZW_Encode++;
          }
          PrefixCode = SuffixCode;
          break;
        }
        if(PrefixTable[RandomIndex] == PrefixCode &&
           SuffixTable[RandomIndex] == SuffixCode)  {
          PrefixCode = EncodeTable[RandomIndex];
          break;
        }
        else  {
          RandomIndex -= Val;
          if(RandomIndex < 0)  RandomIndex += TABLESIZES;
        }
      }
    }
  }
  Code = PrefixCode;
  FillBlockBuf();
  Code = LZW_EofCode;
  FillBlockBuf();

  if(LZW_ShiftBits > 0 || LZW_ByteCount > 0)   {
    BlockBuf[++LZW_ByteCount] = LZW_TempCode & 0x00FF;
    SaveCode();
  }
  fputc(0, fp);
  fputc(';', fp);
}

ClearTable()
{
  LZW_Encode =  LZW_ClearCode +2;
  LZW_RunBits = LZW_BitCode;
  LZW_MaxCodeSize = LZW_ClearCode *2;
  for(i = 0; i < TABLESIZES; i++) EncodeTable[i] = 0;
}

FillBlockBuf()
{
  LZW_TempCode |= (unsigned long)Code << LZW_ShiftBits;
  LZW_ShiftBits += LZW_RunBits;
  while(LZW_ShiftBits >= 8)  {
    BlockBuf[++LZW_ByteCount] = LZW_TempCode & 0x00FF;
    if(LZW_ByteCount == 255)  SaveCode();
    LZW_TempCode >>= 8;
    LZW_ShiftBits -= 8;
  }
}

SaveCode()
{
  BlockBuf[0] = LZW_ByteCount;
  LZW_ByteCount++;
  fwrite(BlockBuf, 1, LZW_ByteCount, fp);
  LZW_ByteCount = 0;
}

